From d316f7c95d4b8b07a5557eb0a39cfa39b7114297 Mon Sep 17 00:00:00 2001 From: John Marino Date: Sun, 9 Feb 2014 15:21:13 +0100 Subject: [PATCH] libutil: Various updates from FreeBSD, esp. pid_* functions It appears that libutil.so is another Frankenstein monster where half of it came from FreeBSD and later it was updated with NetBSD functions. Like libm, this causes problems with syncing later. In order to update the daemon program, the set of pidfile_* functions had to be brought in from FreeBSD. While doing that, I synced with FreeBSD as much as possible. The expand number function was added as well as a dedicated pw_util man page. Specifically ignored were FreeBSD functionality involving kinfo and kld. The login functions are essentially incompatible as the FreeBSD ones require syscntls, so I left the NetBSD versions alone. The various humanize functions that only exist on DragonFly were also left untouched. Collateral damage included: sbin/devd/devd.[ch][ch] (partial sync) usr.sbin/authpf/authpf.c (partial sync) usr.sbin/apmd/apmd.c usr.sbin/battd/battd.c usr.sbin/bthcid/bthcid.c usr.sbin/pflogd/pflogd.c usr.sbin/rwhod/rwhod.c usr.sbin/syslogd/ (full sync) usr.sbin/sysvipcd/sysvipcd.c --- lib/libutil/Makefile | 18 +- lib/libutil/_secure_path.3 | 5 +- lib/libutil/_secure_path.c | 8 +- lib/libutil/auth.c | 4 +- lib/libutil/dehumanize_number.c | 3 +- lib/libutil/expand_number.3 | 87 +++++++ lib/libutil/expand_number.c | 93 +++++++ lib/libutil/flopen.3 | 28 +-- lib/libutil/flopen.c | 26 +- lib/libutil/fparseln.3 | 9 +- lib/libutil/fparseln.c | 18 +- lib/libutil/gr_util.c | 219 +++++++++++----- lib/libutil/hexdump.3 | 2 +- lib/libutil/hexdump.c | 1 + lib/libutil/humanize_number.3 | 136 +++++----- lib/libutil/humanize_number.c | 125 ++++++---- lib/libutil/humanize_unsigned.c | 3 +- lib/libutil/libutil.h | 34 ++- lib/libutil/login.c | 4 +- lib/libutil/login.conf.5 | 167 ++++++++----- lib/libutil/login_auth.3 | 2 +- lib/libutil/login_auth.c | 10 +- lib/libutil/login_cap.3 | 400 ++++++++++++++++++++--------- lib/libutil/login_cap.c | 136 +++++----- lib/libutil/login_cap.h | 106 ++++---- lib/libutil/login_class.c | 126 ++++------ lib/libutil/login_crypt.c | 8 +- lib/libutil/login_ok.3 | 14 +- lib/libutil/login_ok.c | 18 +- lib/libutil/login_times.3 | 4 +- lib/libutil/login_times.c | 40 ++- lib/libutil/login_tty.3 | 15 +- lib/libutil/login_tty.c | 4 +- lib/libutil/logout.c | 4 +- lib/libutil/logwtmp.c | 3 +- lib/libutil/pidfile.3 | 342 +++++++++++++++++++------ lib/libutil/pidfile.c | 307 +++++++++++++++++------ lib/libutil/property.3 | 22 +- lib/libutil/property.c | 101 +++++--- lib/libutil/pty.3 | 69 ++--- lib/libutil/pty.c | 82 ++---- lib/libutil/pw_util.3 | 286 +++++++++++++++++++++ lib/libutil/pw_util.c | 148 +++++++---- lib/libutil/realhostname.3 | 12 +- lib/libutil/realhostname.c | 63 ++--- lib/libutil/realhostname_sa.3 | 14 +- lib/libutil/stub.c | 4 +- lib/libutil/trimdomain.3 | 14 +- lib/libutil/trimdomain.c | 11 +- lib/libutil/uucplock.3 | 20 +- lib/libutil/uucplock.c | 30 ++- sbin/devd/devd.cc | 125 +++++++--- sbin/devd/devd.hh | 10 +- usr.sbin/apmd/apmd.c | 4 +- usr.sbin/authpf/authpf.c | 56 ++--- usr.sbin/battd/battd.c | 5 +- usr.sbin/bthcid/bthcid.c | 12 +- usr.sbin/pflogd/pflogd.c | 4 +- usr.sbin/rwhod/rwhod.c | 4 +- usr.sbin/syslogd/Makefile | 9 +- usr.sbin/syslogd/pathnames.h | 7 +- usr.sbin/syslogd/syslog.conf.5 | 36 ++- usr.sbin/syslogd/syslogd.8 | 38 ++- usr.sbin/syslogd/syslogd.c | 428 ++++++++++++++------------------ usr.sbin/sysvipcd/sysvipcd.c | 4 +- 65 files changed, 2675 insertions(+), 1472 deletions(-) create mode 100644 lib/libutil/expand_number.3 create mode 100644 lib/libutil/expand_number.c create mode 100644 lib/libutil/pw_util.3 diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile index 3d6dcdb3be..4fa15dba66 100644 --- a/lib/libutil/Makefile +++ b/lib/libutil/Makefile @@ -1,5 +1,5 @@ # @(#)Makefile 8.1 (Berkeley) 6/4/93 -# $FreeBSD: src/lib/libutil/Makefile,v 1.33.2.4 2001/04/25 10:04:42 ru Exp $ +# $FreeBSD: head/lib/libutil/Makefile 242381 2012-10-30 22:18:08Z bapt $ LIB= util SHLIB_MAJOR= 4 @@ -12,7 +12,7 @@ SRCS= flopen.c login.c login_tty.c logout.c logwtmp.c logwtmpx.c pty.c \ realhostname.c fparseln.c stub.c pidfile.c trimdomain.c \ dehumanize_number.c humanize_number.c humanize_unsigned.c pw_util.c \ efun.c getmntopts.c -SRCS+= gr_util.c hexdump.c +SRCS+= gr_util.c hexdump.c expand_number.c INCS= libutil.h login_cap.h INCSLINKS=libutil.h ${INCLUDEDIR}/util.h @@ -29,6 +29,7 @@ MAN+= flopen.3 login.3 loginx.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 \ efun.3 getmntopts.3 MAN+= login.conf.5 auth.conf.5 MAN+= hexdump.3 +MAN+= pw_util.3 MLINKS+=auth.3 auth_getval.3 MLINKS+=efun.3 ecalloc.3 efun.3 emalloc.3 efun.3 erealloc.3 efun.3 esetfunc.3 \ @@ -57,5 +58,18 @@ MLINKS+=property.3 property_find.3 MLINKS+=pty.3 openpty.3 pty.3 forkpty.3 MLINKS+=uucplock.3 uu_lock.3 uucplock.3 uu_lock_txfr.3 \ uucplock.3 uu_unlock.3 uucplock.3 uu_lockerr.3 +MLINKS+=pw_util.3 pw_copy.3 \ + pw_util.3 pw_dup.3 \ + pw_util.3 pw_edit.3 \ + pw_util.3 pw_equal.3 \ + pw_util.3 pw_fini.3 \ + pw_util.3 pw_init.3 \ + pw_util.3 pw_make.3 \ + pw_util.3 pw_make_v7.3 \ + pw_util.3 pw_mkdb.3 \ + pw_util.3 pw_lock.3 \ + pw_util.3 pw_scan.3 \ + pw_util.3 pw_tempname.3 \ + pw_util.3 pw_tmp.3 .include diff --git a/lib/libutil/_secure_path.3 b/lib/libutil/_secure_path.3 index 18a29779d9..e9db2c005c 100644 --- a/lib/libutil/_secure_path.3 +++ b/lib/libutil/_secure_path.3 @@ -17,7 +17,7 @@ .\" 5. Modifications may be freely made to this file providing the above .\" conditions are met. .\" -.\" $FreeBSD: src/lib/libutil/_secure_path.3,v 1.7.2.4 2002/03/19 01:49:54 dd Exp $ +.\" $FreeBSD: head/lib/libutil/_secure_path.3 206622 2010-04-14 19:08:06Z uqs $ .\" .Dd May 2, 1997 .Dt _SECURE_PATH 3 @@ -58,8 +58,9 @@ gid, if gid is not -1. This function returns zero if the file exists and may be considered secure, -2 if the file does not exist, and -1 otherwise to indicate a security failure. +The .Xr syslog 3 -is used to log any failure of this function, including the +function is used to log any failure of this function, including the reason, at LOG_ERR priority. .Sh SEE ALSO .Xr lstat 2 , diff --git a/lib/libutil/_secure_path.c b/lib/libutil/_secure_path.c index 0a811c8fee..576aff2caa 100644 --- a/lib/libutil/_secure_path.c +++ b/lib/libutil/_secure_path.c @@ -18,8 +18,7 @@ * 5. Modifications may be freely made to this file providing the above * conditions are met. * - * $FreeBSD: src/lib/libutil/_secure_path.c,v 1.5 1999/08/28 00:05:42 peter Exp $ - * $DragonFly: src/lib/libutil/_secure_path.c,v 1.4 2008/10/29 22:03:12 swildner Exp $ + * $FreeBSD: head/lib/libutil/_secure_path.c 139012 2004-12-18 12:31:12Z ru $ */ @@ -27,15 +26,14 @@ #include #include +#include #include -#include "libutil.h" - /* * Check for common security problems on a given path * It must be: * 1. A regular file, and exists - * 2. Owned and writaable only by root (or given owner) + * 2. Owned and writable only by root (or given owner) * 3. Group ownership is given group or is non-group writable * * Returns: -2 if file does not exist, diff --git a/lib/libutil/auth.c b/lib/libutil/auth.c index 80206c803c..c763b388f8 100644 --- a/lib/libutil/auth.c +++ b/lib/libutil/auth.c @@ -29,7 +29,6 @@ * SUCH DAMAGE. * * $FreeBSD: src/lib/libutil/auth.c,v 1.3.6.1 2001/03/05 06:29:52 kris Exp $ - * $DragonFly: src/lib/libutil/auth.c,v 1.3 2005/03/04 04:31:11 cpressey Exp $ * */ @@ -39,8 +38,7 @@ #include #include #include - -#include "libutil.h" +#include static properties P; diff --git a/lib/libutil/dehumanize_number.c b/lib/libutil/dehumanize_number.c index da80fbf209..1905c0a13d 100644 --- a/lib/libutil/dehumanize_number.c +++ b/lib/libutil/dehumanize_number.c @@ -36,8 +36,7 @@ #include #include #include - -#include "libutil.h" +#include /* * Converts the number given in 'str', which may be given in a humanized diff --git a/lib/libutil/expand_number.3 b/lib/libutil/expand_number.3 new file mode 100644 index 0000000000..895e3720f9 --- /dev/null +++ b/lib/libutil/expand_number.3 @@ -0,0 +1,87 @@ +.\" Copyright (c) 2007 Eric Anderson +.\" Copyright (c) 2007 Pawel Jakub Dawidek +.\" 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 AUTHORS 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 AUTHORS 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. +.\" +.\" $FreeBSD: head/lib/libutil/expand_number.3 258026 2013-11-12 00:56:22Z eadler $ +.\" +.Dd August 15, 2010 +.Dt EXPAND_NUMBER 3 +.Os +.Sh NAME +.Nm expand_number +.Nd format a number from human readable form +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In libutil.h +.Ft int +.Fo expand_number +.Fa "const char *buf" "uint64_t *num" +.Fc +.Sh DESCRIPTION +The +.Fn expand_number +function unformats the +.Fa buf +string and stores a unsigned 64-bit quantity at address pointed out by the +.Fa num +argument. +.Pp +The +.Fn expand_number +function +is case-insensitive and +follows the SI power of two convention. +.Pp +The prefixes are: +.Bl -column "Prefix" "Description" "1000000000000000000" -offset indent +.It Sy "Prefix" Ta Sy "Description" Ta Sy "Multiplier" +.It Li K Ta No kilo Ta 1024 +.It Li M Ta No mega Ta 1048576 +.It Li G Ta No giga Ta 1073741824 +.It Li T Ta No tera Ta 1099511627776 +.It Li P Ta No peta Ta 1125899906842624 +.It Li E Ta No exa Ta 1152921504606846976 +.El +.Sh RETURN VALUES +.Rv -std +.Sh ERRORS +The +.Fn expand_number +function will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The given string contains no digits. +.It Bq Er EINVAL +An unrecognized prefix was given. +.It Bq Er ERANGE +Result doesn't fit into 64 bits. +.El +.Sh SEE ALSO +.Xr humanize_number 3 +.Sh HISTORY +The +.Fn expand_number +function first appeared in +.Fx 6.3 . diff --git a/lib/libutil/expand_number.c b/lib/libutil/expand_number.c new file mode 100644 index 0000000000..fc099f7461 --- /dev/null +++ b/lib/libutil/expand_number.c @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 2007 Eric Anderson + * Copyright (c) 2007 Pawel Jakub Dawidek + * 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 AUTHORS 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 AUTHORS 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. + * + * $FreeBSD: head/lib/libutil/expand_number.c 255069 2013-08-30 11:21:52Z pluknet $ + */ + + +#include +#include +#include +#include +#include +#include + +int +expand_number(const char *buf, uint64_t *num) +{ + char *endptr; + uintmax_t umaxval; + uint64_t number; + unsigned shift; + int serrno; + + serrno = errno; + errno = 0; + umaxval = strtoumax(buf, &endptr, 0); + if (umaxval > UINT64_MAX) + errno = ERANGE; + if (errno != 0) + return (-1); + errno = serrno; + number = umaxval; + + switch (tolower((unsigned char)*endptr)) { + case 'e': + shift = 60; + break; + case 'p': + shift = 50; + break; + case 't': + shift = 40; + break; + case 'g': + shift = 30; + break; + case 'm': + shift = 20; + break; + case 'k': + shift = 10; + break; + case 'b': + case '\0': /* No unit. */ + *num = number; + return (0); + default: + /* Unrecognized unit. */ + errno = EINVAL; + return (-1); + } + + if ((number << shift) >> shift != number) { + /* Overflow */ + errno = ERANGE; + return (-1); + } + *num = number << shift; + return (0); +} diff --git a/lib/libutil/flopen.3 b/lib/libutil/flopen.3 index 41c5139a30..c3d97e823f 100644 --- a/lib/libutil/flopen.3 +++ b/lib/libutil/flopen.3 @@ -23,9 +23,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libutil/flopen.3,v 1.7 2008/10/20 18:02:16 des Exp $ +.\" $FreeBSD: head/lib/libutil/flopen.3 229784 2012-01-07 16:13:56Z uqs $ .\" -.Dd December 27, 2008 +.Dd June 6, 2009 .Dt FLOPEN 3 .Os .Sh NAME @@ -46,13 +46,12 @@ The function opens or creates a file and acquires an exclusive lock on it. It is essentially equivalent with calling .Fn open -with the same parameters followed by an -.Fn fcntl -.Dv F_SETLK -or -.Dv F_SETLKW -operation with lock type -.Dv F_WRLCK , +with the same parameters followed by +.Fn flock +with an +.Va operation +argument of +.Dv LOCK_EX , except that .Fn flopen will attempt to detect and handle races that may occur between opening @@ -70,7 +69,7 @@ and the file is already locked, will fail and set .Va errno to -.Er EWOULDBLOCK . +.Dv EWOULDBLOCK . .Pp As with .Fn open , @@ -87,18 +86,13 @@ returns a valid file descriptor. Otherwise, it returns -1, and sets .Va errno as described in -.Xr fcntl 2 +.Xr flock 2 and .Xr open 2 . .Sh SEE ALSO .Xr errno 2 , -.Xr fcntl 2 , +.Xr flock 2 , .Xr open 2 -.Sh HISTORY -The -.Fn flopen -function first appeared in -.Fx 6.3 . .Sh AUTHORS .An -nosplit The diff --git a/lib/libutil/flopen.c b/lib/libutil/flopen.c index 0564489aae..b3ef6dcc85 100644 --- a/lib/libutil/flopen.c +++ b/lib/libutil/flopen.c @@ -24,24 +24,21 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libutil/flopen.c,v 1.11 2008/10/20 18:11:30 des Exp $ + * $FreeBSD: head/lib/libutil/flopen.c 193591 2009-06-06 18:47:03Z des $ */ #include #include -#include #include -#include #include - +#include #include int flopen(const char *path, int flags, ...) { int fd, operation, serrno, trunc; - struct flock lock; struct stat sb, fsb; mode_t mode; @@ -58,10 +55,9 @@ flopen(const char *path, int flags, ...) va_end(ap); } - memset(&lock, 0, sizeof lock); - lock.l_type = ((flags & O_ACCMODE) == O_RDONLY) ? F_RDLCK : F_WRLCK; - lock.l_whence = SEEK_SET; - operation = (flags & O_NONBLOCK) ? F_SETLK : F_SETLKW; + operation = LOCK_EX; + if (flags & O_NONBLOCK) + operation |= LOCK_NB; trunc = (flags & O_TRUNC); flags &= ~O_TRUNC; @@ -70,35 +66,35 @@ flopen(const char *path, int flags, ...) if ((fd = open(path, flags, mode)) == -1) /* non-existent or no access */ return (-1); - if (fcntl(fd, operation, &lock) == -1) { + if (flock(fd, operation) == -1) { /* unsupported or interrupted */ serrno = errno; - close(fd); + (void)close(fd); errno = serrno; return (-1); } if (stat(path, &sb) == -1) { /* disappeared from under our feet */ - close(fd); + (void)close(fd); continue; } if (fstat(fd, &fsb) == -1) { /* can't happen [tm] */ serrno = errno; - close(fd); + (void)close(fd); errno = serrno; return (-1); } if (sb.st_dev != fsb.st_dev || sb.st_ino != fsb.st_ino) { /* changed under our feet */ - close(fd); + (void)close(fd); continue; } if (trunc && ftruncate(fd, 0) != 0) { /* can't happen [tm] */ serrno = errno; - close(fd); + (void)close(fd); errno = serrno; return (-1); } diff --git a/lib/libutil/fparseln.3 b/lib/libutil/fparseln.3 index a0c1b624fc..a634722436 100644 --- a/lib/libutil/fparseln.3 +++ b/lib/libutil/fparseln.3 @@ -1,6 +1,5 @@ .\" $NetBSD: fparseln.3,v 1.7 1999/07/02 15:49:12 simonb Exp $ -.\" $FreeBSD: src/lib/libutil/fparseln.3,v 1.5.2.4 2001/12/17 10:08:32 ru Exp $ -.\" $DragonFly: src/lib/libutil/fparseln.3,v 1.3 2006/03/26 22:56:56 swildner Exp $ +.\" $FreeBSD: head/lib/libutil/fparseln.3 140081 2005-01-11 20:50:51Z ru $ .\" .\" Copyright (c) 1997 Christos Zoulas. All rights reserved. .\" @@ -38,7 +37,6 @@ .Sh LIBRARY .Lb libutil .Sh SYNOPSIS -.In sys/types.h .In stdio.h .In libutil.h .Ft "char *" @@ -124,6 +122,7 @@ Remove escape preceding any other character. .It Dv FPARSELN_UNESCALL All of the above. .El +.Pp .El .Sh RETURN VALUES Upon successful completion a pointer to the parsed line is returned; @@ -154,4 +153,6 @@ if it runs out of memory. The .Fn fparseln function first appeared in -.Nx 1.4 . +.Nx 1.4 +and +.Fx 4.0 . diff --git a/lib/libutil/fparseln.c b/lib/libutil/fparseln.c index 238c08f341..183f2ecac5 100644 --- a/lib/libutil/fparseln.c +++ b/lib/libutil/fparseln.c @@ -1,6 +1,4 @@ /* $NetBSD: fparseln.c,v 1.9 1999/09/20 04:48:06 lukem Exp $ */ -/* $FreeBSD: src/lib/libutil/fparseln.c,v 1.2 1999/12/29 17:50:33 peter Exp $ */ -/* $DragonFly: src/lib/libutil/fparseln.c,v 1.6 2005/03/16 06:35:48 cpressey Exp $ */ /* * Copyright (c) 1997 Christos Zoulas. All rights reserved. @@ -30,20 +28,18 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libutil/fparseln.c,v 1.2 1999/12/29 17:50:33 peter Exp $ + * $FreeBSD: head/lib/libutil/fparseln.c 121193 2003-10-18 10:04:16Z markm $ */ #include - #include #include #include -#include #include +#include +#include -#include "libutil.h" - -static int isescaped (const char *, const char *, int); +static int isescaped(const char *, const char *, int); /* isescaped(): * Return true if the character in *p that belongs to a string @@ -55,8 +51,10 @@ isescaped(const char *sp, const char *p, int esc) const char *cp; size_t ne; +#if 0 _DIAGASSERT(sp != NULL); _DIAGASSERT(p != NULL); +#endif /* No escape character */ if (esc == '\0') @@ -87,7 +85,9 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags) int cnt; char esc, con, nl, com; +#if 0 _DIAGASSERT(fp != NULL); +#endif len = 0; buf = NULL; @@ -192,7 +192,7 @@ fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags) #ifdef TEST int -main(int argc, char **argv) +main(int argc, char *argv[]) { char *ptr; size_t size, line; diff --git a/lib/libutil/gr_util.c b/lib/libutil/gr_util.c index 4d035d60e1..7b89302037 100644 --- a/lib/libutil/gr_util.c +++ b/lib/libutil/gr_util.c @@ -22,6 +22,8 @@ * 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. + * + * $FreeBSD: head/lib/libutil/gr_util.c 248102 2013-03-09 13:30:06Z db $ */ #include @@ -41,18 +43,13 @@ #include #include -struct group_storage { - struct group gr; - char *members[]; -}; - static int lockfd = -1; static char group_dir[PATH_MAX]; static char group_file[PATH_MAX]; static char tempname[PATH_MAX]; static int initialized; - -static const char group_line_format[] = "%s:%s:%ju:"; +static size_t grmemlen(const struct group *, const char *, int *); +static struct group *grcopy(const struct group *gr, char *mem, const char *, int ndx); /* * Initialize statics @@ -103,10 +100,8 @@ gr_lock(void) for (;;) { struct stat st; - lockfd = open(group_file, O_RDONLY, 0); - if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) - err(1, "%s", group_file); - if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) { + lockfd = flopen(group_file, O_RDONLY|O_NONBLOCK|O_CLOEXEC, 0); + if (lockfd == -1) { if (errno == EWOULDBLOCK) { errx(1, "the group file is busy"); } else { @@ -315,11 +310,14 @@ gr_copy(int ffd, int tfd, const struct group *gr, struct group *old_gr) int gr_mkdb(void) { + if (chmod(tempname, 0644) != 0) + return (-1); + return (rename(tempname, group_file)); } /* - * Clean up. Preserver errno for the caller's convenience. + * Clean up. Preserves errno for the caller's convenience. */ void gr_fini(void) @@ -347,7 +345,6 @@ gr_equal(const struct group *gr1, const struct group *gr2) { int gr1_ndx; int gr2_ndx; - bool found; /* Check that the non-member information is the same. */ if (gr1->gr_name == NULL || gr2->gr_name == NULL) { @@ -363,28 +360,30 @@ gr_equal(const struct group *gr1, const struct group *gr2) if (gr1->gr_gid != gr2->gr_gid) return (false); - /* Check all members in both groups. */ - if (gr1->gr_mem == NULL || gr2->gr_mem == NULL) { - if (gr1->gr_mem != gr2->gr_mem) + /* Check all members in both groups. + * getgrnam can return gr_mem with a pointer to NULL. + * gr_dup and gr_add strip out this superfluous NULL, setting + * gr_mem to NULL for no members. + */ + if (gr1->gr_mem != NULL && gr2->gr_mem != NULL) { + int i; + + for (i = 0; gr1->gr_mem[i] != NULL; i++) { + if (strcmp(gr1->gr_mem[i], gr2->gr_mem[i]) != 0) return (false); - } else { - for (found = false, gr1_ndx = 0; gr1->gr_mem[gr1_ndx] != NULL; - gr1_ndx++) { - for (gr2_ndx = 0; gr2->gr_mem[gr2_ndx] != NULL; - gr2_ndx++) - if (strcmp(gr1->gr_mem[gr1_ndx], - gr2->gr_mem[gr2_ndx]) == 0) { - found = true; - break; } - if (!found) - return (false); } - - /* Check that group2 does not have more members than group1. */ - if (gr2->gr_mem[gr1_ndx] != NULL) + /* Count number of members in both structs */ + gr2_ndx = 0; + if (gr2->gr_mem != NULL) + for(; gr2->gr_mem[gr2_ndx] != NULL; gr2_ndx++) + /* empty */; + gr1_ndx = 0; + if (gr1->gr_mem != NULL) + for(; gr1->gr_mem[gr1_ndx] != NULL; gr1_ndx++) + /* empty */; + if (gr1_ndx != gr2_ndx) return (false); - } return (true); } @@ -395,7 +394,10 @@ gr_equal(const struct group *gr1, const struct group *gr2) char * gr_make(const struct group *gr) { + const char *group_line_format = "%s:%s:%ju:"; + const char *sep; char *line; + char *p; size_t line_size; int ndx; @@ -410,15 +412,17 @@ gr_make(const struct group *gr) } /* Create the group line and fill it. */ - if ((line = malloc(line_size)) == NULL) + if ((line = p = malloc(line_size)) == NULL) return (NULL); - snprintf(line, line_size, group_line_format, gr->gr_name, gr->gr_passwd, + p += sprintf(p, group_line_format, gr->gr_name, gr->gr_passwd, (uintmax_t)gr->gr_gid); - if (gr->gr_mem != NULL) + if (gr->gr_mem != NULL) { + sep = ""; for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) { - strcat(line, gr->gr_mem[ndx]); - if (gr->gr_mem[ndx + 1] != NULL) - strcat(line, ","); + p = stpcpy(p, sep); + p = stpcpy(p, gr->gr_mem[ndx]); + sep = ","; + } } return (line); @@ -430,48 +434,129 @@ gr_make(const struct group *gr) struct group * gr_dup(const struct group *gr) { - char *dst; + return (gr_add(gr, NULL)); +} +/* + * Add a new member name to a struct group. + */ +struct group * +gr_add(const struct group *gr, const char *newmember) +{ + char *mem; size_t len; - struct group_storage *gs; - int ndx; int num_mem; + num_mem = 0; + len = grmemlen(gr, newmember, &num_mem); + /* Create new group and copy old group into it. */ + if ((mem = malloc(len)) == NULL) + return (NULL); + return (grcopy(gr, mem, newmember, num_mem)); +} + +/* It is safer to walk the pointers given at gr_mem since there is no + * guarantee the gr_mem + strings are contiguous in the given struct group + * but compactify the new group into the following form. + * + * The new struct is laid out like this in memory. The example given is + * for a group with two members only. + * + * { + * (char *name) + * (char *passwd) + * (int gid) + * (gr_mem * newgrp + sizeof(struct group) + sizeof(**)) points to gr_mem area + * gr_mem area + * (member1 *) + * (member2 *) + * (NULL) + * (name string) + * (passwd string) + * (member1 string) + * (member2 string) + * } + */ +/* + * Copy the contents of a group plus given name to a preallocated group struct + */ +static struct group * +grcopy(const struct group *gr, char *dst, const char *name, int ndx) +{ + int i; + struct group *newgr; + + newgr = (struct group *)(void *)dst; /* avoid alignment warning */ + dst += sizeof(*newgr); + if (ndx != 0) { + newgr->gr_mem = (char **)(void *)(dst); /* avoid alignment warning */ + dst += (ndx + 1) * sizeof(*newgr->gr_mem); + } else + newgr->gr_mem = NULL; + if (gr->gr_name != NULL) { + newgr->gr_name = dst; + dst = stpcpy(dst, gr->gr_name) + 1; + } else + newgr->gr_name = NULL; + if (gr->gr_passwd != NULL) { + newgr->gr_passwd = dst; + dst = stpcpy(dst, gr->gr_passwd) + 1; + } else + newgr->gr_passwd = NULL; + newgr->gr_gid = gr->gr_gid; + i = 0; + /* Original group struct might have a NULL gr_mem */ + if (gr->gr_mem != NULL) { + for (; gr->gr_mem[i] != NULL; i++) { + newgr->gr_mem[i] = dst; + dst = stpcpy(dst, gr->gr_mem[i]) + 1; + } + } + /* If name is not NULL, newgr->gr_mem is known to be not NULL */ + if (name != NULL) { + newgr->gr_mem[i++] = dst; + dst = stpcpy(dst, name) + 1; + } + /* if newgr->gr_mem is not NULL add NULL marker */ + if (newgr->gr_mem != NULL) + newgr->gr_mem[i] = NULL; + + return (newgr); +} + +/* + * Calculate length of a struct group + given name + */ +static size_t +grmemlen(const struct group *gr, const char *name, int *num_mem) +{ + size_t len; + int i; + + if (gr == NULL) + return (0); /* Calculate size of the group. */ - len = sizeof(*gs); + len = sizeof(*gr); if (gr->gr_name != NULL) len += strlen(gr->gr_name) + 1; if (gr->gr_passwd != NULL) len += strlen(gr->gr_passwd) + 1; + i = 0; if (gr->gr_mem != NULL) { - for (num_mem = 0; gr->gr_mem[num_mem] != NULL; num_mem++) - len += strlen(gr->gr_mem[num_mem]) + 1; - len += (num_mem + 1) * sizeof(*gr->gr_mem); - } else - num_mem = -1; - - /* Create new group and copy old group into it. */ - if ((gs = calloc(1, len)) == NULL) - return (NULL); - dst = (char *)&gs->members[num_mem + 1]; - if (gr->gr_name != NULL) { - gs->gr.gr_name = dst; - dst = stpcpy(gs->gr.gr_name, gr->gr_name) + 1; + for (; gr->gr_mem[i] != NULL; i++) { + len += strlen(gr->gr_mem[i]) + 1; + len += sizeof(*gr->gr_mem); } - if (gr->gr_passwd != NULL) { - gs->gr.gr_passwd = dst; - dst = stpcpy(gs->gr.gr_passwd, gr->gr_passwd) + 1; } - gs->gr.gr_gid = gr->gr_gid; - if (gr->gr_mem != NULL) { - gs->gr.gr_mem = gs->members; - for (ndx = 0; ndx < num_mem; ndx++) { - gs->gr.gr_mem[ndx] = dst; - dst = stpcpy(gs->gr.gr_mem[ndx], gr->gr_mem[ndx]) + 1; + if (name != NULL) { + i++; + len += strlen(name) + 1; + len += sizeof(*gr->gr_mem); } - gs->gr.gr_mem[ndx] = NULL; - } - - return (&gs->gr); + /* Allow for NULL pointer */ + if (i != 0) + len += sizeof(*gr->gr_mem); + *num_mem = i; + return(len); } /* diff --git a/lib/libutil/hexdump.3 b/lib/libutil/hexdump.3 index 8eb3508a2b..9f74d7241d 100644 --- a/lib/libutil/hexdump.3 +++ b/lib/libutil/hexdump.3 @@ -26,7 +26,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD$ +.\" $FreeBSD: head/lib/libutil/hexdump.3 206622 2010-04-14 19:08:06Z uqs $ .\" .Dd November 3, 2012 .Dt HEXDUMP 3 diff --git a/lib/libutil/hexdump.c b/lib/libutil/hexdump.c index f81930d17d..50f2b9e9dd 100644 --- a/lib/libutil/hexdump.c +++ b/lib/libutil/hexdump.c @@ -32,6 +32,7 @@ * SUCH DAMAGE. * * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 + * $FreeBSD: head/lib/libutil/hexdump.c 180161 2008-07-01 22:30:57Z jhb $ */ #include diff --git a/lib/libutil/humanize_number.3 b/lib/libutil/humanize_number.3 index 04abe0abfa..999d586b63 100644 --- a/lib/libutil/humanize_number.3 +++ b/lib/libutil/humanize_number.3 @@ -1,6 +1,5 @@ -.\" $NetBSD: humanize_number.3,v 1.5 2005/04/11 12:19:16 wiz Exp $ -.\" $FreeBSD: src/lib/libutil/humanize_number.3,v 1.12 2007/09/28 15:31:44 obrien Exp $ -.\" $DragonFly: src/lib/libutil/humanize_number.3,v 1.4 2008/09/14 20:04:59 swildner Exp $ +.\" $NetBSD: humanize_number.3,v 1.4 2003/04/16 13:34:37 wiz Exp $ +.\" $FreeBSD: head/lib/libutil/humanize_number.3 256130 2013-10-07 22:22:57Z jmg $ .\" .\" Copyright (c) 1999, 2002 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -29,21 +28,17 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd September 14, 2008 +.Dd October 7, 2013 .Dt HUMANIZE_NUMBER 3 .Os .Sh NAME -.Nm dehumanize_number , .Nm humanize_number -.Nd format a number into a human readable form and vice versa +.Nd format a number into a human readable form .Sh LIBRARY .Lb libutil .Sh SYNOPSIS -.In sys/types.h .In libutil.h .Ft int -.Fn dehumanize_number "const char *str" "int64_t *result" -.Ft int .Fo humanize_number .Fa "char *buf" "size_t len" "int64_t number" "const char *suffix" .Fa "int scale" "int flags" @@ -51,15 +46,15 @@ .Sh DESCRIPTION The .Fn humanize_number -function formats the signed 64 bit quantity given in +function formats the signed 64-bit quantity given in .Fa number into -.Fa buffer . +.Fa buf . A space and then .Fa suffix is appended to the end. The buffer pointed to by -.Fa buffer +.Fa buf must be at least .Fa len bytes long. @@ -67,23 +62,30 @@ bytes long. If the formatted number (including .Fa suffix ) would be too long to fit into -.Fa buffer , +.Fa buf , then divide .Fa number by 1024 until it will. In this case, prefix .Fa suffix -with the appropriate SI designator. +with the appropriate designator. The .Fn humanize_number -function -follows the traditional computer science conventions rather than the proposed -SI power of two convention. +function follows the traditional computer science conventions by +default, rather than the IEE/IEC (and now also SI) power of two +convention or the power of ten notion. +This behaviour however can be altered by specifying the +.Dv HN_DIVISOR_1000 +and +.Dv HN_IEC_PREFIXES +flags. .Pp -The prefixes are: +The traditional +.Pq default +prefixes are: .Bl -column "Prefix" "Description" "1000000000000000000" -offset indent .It Sy "Prefix" Ta Sy "Description" Ta Sy "Multiplier" Ta Sy "Multiplier 1000x" -.It Li k Ta No kilo Ta 1024 Ta 1000 +.It Li (note) Ta No kilo Ta 1024 Ta 1000 .It Li M Ta No mega Ta 1048576 Ta 1000000 .It Li G Ta No giga Ta 1073741824 Ta 1000000000 .It Li T Ta No tera Ta 1099511627776 Ta 1000000000000 @@ -91,15 +93,34 @@ The prefixes are: .It Li E Ta No exa Ta 1152921504606846976 Ta 1000000000000000000 .El .Pp +Note: +An uppercase K indicates a power of two, a lowercase k a power of ten. +.Pp +The IEE/IEC (and now also SI) power of two prefixes are: +.Bl -column "Prefix" "Description" "1000000000000000000" -offset indent +.It Sy "Prefix" Ta Sy "Description" Ta Sy "Multiplier" +.It Li Ki Ta No kibi Ta 1024 +.It Li Mi Ta No mebi Ta 1048576 +.It Li Gi Ta No gibi Ta 1073741824 +.It Li Ti Ta No tebi Ta 1099511627776 +.It Li Pi Ta No pebi Ta 1125899906842624 +.It Li Ei Ta No exbi Ta 1152921504606846976 +.El +.Pp The .Fa len argument must be at least 4 plus the length of .Fa suffix , in order to ensure a useful result is generated into -.Fa buffer . +.Fa buf . To use a specific prefix, specify this as .Fa scale -(multiplier = 1024 ^ scale). +.Po multiplier = 1024 ^ scale; +when +.Dv HN_DIVISOR_1000 +is specified, +multiplier = 1000 ^ scale +.Pc . This cannot be combined with any of the .Fa scale flags below. @@ -119,7 +140,7 @@ The following flags may be passed in .Fa flags : .Bl -tag -width ".Dv HN_DIVISOR_1000" -offset indent .It Dv HN_DECIMAL -If the final result is less than 10, display it using one digit. +If the final result is less than 10, display it using one decimal place. .It Dv HN_NOSPACE Do not put a space between .Fa number @@ -132,50 +153,42 @@ Use Divide .Fa number with 1000 instead of 1024. +.It Dv HN_IEC_PREFIXES +Use the IEE/IEC notion of prefixes (Ki, Mi, Gi...). +This flag has no effect when +.Dv HN_DIVISOR_1000 +is also specified. .El -.Pp -The -.Fn dehumanize_number -function parses the string representing an integral value given in -.Fa str -and stores the numerical value in the integer pointed to by -.Fa result . -The provided string may hold one of the suffixes, which will be interpreted -and used to scale up its accompanying numerical value. .Sh RETURN VALUES -The -.Fn humanize_number -function returns the number of characters stored in -.Fa buffer +Upon success, the +.Nm +function returns the number of characters that would have been stored in +.Fa buf (excluding the terminating .Dv NUL ) -upon success, or \-1 upon failure. +if +.Fa buf +was large enough, or \-1 upon failure. +Even upon failure, the contents of +.Fa buf +may be modified. If .Dv HN_GETSCALE is specified, the prefix index number will be returned instead. -.Pp -The -.Fn dehumanize_number -function returns 0 if the string was parsed correctly. -A \-1 is returned to indicate failure and an error code is stored in -.Va errno . -.Sh ERRORS +.Sh SEE ALSO +.Xr expand_number 3 +.Sh STANDARDS The -.Fn dehumanize_number -function will fail and no number will be stored in -.Fa result -if: -.Bl -tag -width Er -.It Bq Er EINVAL -The string in -.Fa str -was empty or carried an unknown suffix. -.It Bq Er ERANGE -The string in -.Fa str -represented a number that does not fit in -.Fa result . -.El +.Dv HN_DIVISOR_1000 +and +.Dv HN_IEC_PREFIXES +flags +conform to +.Tn ISO/IEC +Std\~80000-13:2008 +and +.Tn IEEE +Std\~1541-2002. .Sh HISTORY The .Fn humanize_number @@ -183,8 +196,7 @@ function first appeared in .Nx 2.0 and then in .Fx 5.3 . -.Pp The -.Fn dehumanize_number -function first appeared in -.Nx 5.0 . +.Dv HN_IEC_PREFIXES +flag was introduced in +.Fx 9.0 . diff --git a/lib/libutil/humanize_number.c b/lib/libutil/humanize_number.c index 8ea1041a3c..a2f0830e6b 100644 --- a/lib/libutil/humanize_number.c +++ b/lib/libutil/humanize_number.c @@ -1,8 +1,8 @@ /* $NetBSD: humanize_number.c,v 1.14 2008/04/28 20:22:59 martin Exp $ */ -/* $DragonFly: src/lib/libutil/humanize_number.c,v 1.3 2008/08/04 19:09:26 swildner Exp $ */ /* * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc. + * Copyright 2013 John-Mark Gurney * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -30,7 +30,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libutil/humanize_number.c,v 1.3 2008/03/08 21:55:59 antoine Exp $ + * $FreeBSD: head/lib/libutil/humanize_number.c 256130 2013-10-07 22:22:57Z jmg $ */ #include @@ -40,61 +40,83 @@ #include #include #include +#include -#include "libutil.h" +static const int maxscale = 7; int -humanize_number(char *buf, size_t len, int64_t bytes, +humanize_number(char *buf, size_t len, int64_t quotient, const char *suffix, int scale, int flags) { const char *prefixes, *sep; - int b, i, r, maxscale, s1, s2, sign; + int i, r, remainder, s1, s2, sign; + int divisordeccut; int64_t divisor, max; size_t baselen; - assert(buf != NULL); - assert(suffix != NULL); - assert(scale >= 0); + /* Since so many callers don't check -1, NUL terminate the buffer */ + if (len > 0) + buf[0] = '\0'; + + /* validate args */ + if (buf == NULL || suffix == NULL) + return (-1); + if (scale < 0) + return (-1); + else if (scale >= maxscale && + ((scale & ~(HN_AUTOSCALE|HN_GETSCALE)) != 0)) + return (-1); + if ((flags & HN_DIVISOR_1000) && (flags & HN_IEC_PREFIXES)) + return (-1); + + /* setup parameters */ + remainder = 0; + if (flags & HN_IEC_PREFIXES) { + baselen = 2; + /* + * Use the prefixes for power of two recommended by + * the International Electrotechnical Commission + * (IEC) in IEC 80000-3 (i.e. Ki, Mi, Gi...). + * + * HN_IEC_PREFIXES implies a divisor of 1024 here + * (use of HN_DIVISOR_1000 would have triggered + * an assertion earlier). + */ + divisor = 1024; + divisordeccut = 973; /* ceil(.95 * 1024) */ + if (flags & HN_B) + prefixes = "B\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei"; + else + prefixes = "\0\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei"; + } else { + baselen = 1; if (flags & HN_DIVISOR_1000) { - /* SI for decimal multiplies */ divisor = 1000; + divisordeccut = 950; if (flags & HN_B) - prefixes = "B\0k\0M\0G\0T\0P\0E"; + prefixes = "B\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E"; else - prefixes = "\0\0k\0M\0G\0T\0P\0E"; + prefixes = "\0\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E"; } else { - /* - * binary multiplies - * XXX IEC 60027-2 recommends Ki, Mi, Gi... - */ divisor = 1024; + divisordeccut = 973; /* ceil(.95 * 1024) */ if (flags & HN_B) - prefixes = "B\0K\0M\0G\0T\0P\0E"; + prefixes = "B\0\0K\0\0M\0\0G\0\0T\0\0P\0\0E"; else - prefixes = "\0\0K\0M\0G\0T\0P\0E"; + prefixes = "\0\0\0K\0\0M\0\0G\0\0T\0\0P\0\0E"; + } } -#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1]) - maxscale = 7; +#define SCALE2PREFIX(scale) (&prefixes[(scale) * 3]) - if (scale >= maxscale && - (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0) - return (-1); - - if (buf == NULL || suffix == NULL) - return (-1); - - if (len > 0) - buf[0] = '\0'; - if (bytes < 0) { + if (quotient < 0) { sign = -1; - bytes *= -100; - baselen = 3; /* sign, digit, prefix */ + quotient = -quotient; + baselen += 2; /* sign, digit */ } else { sign = 1; - bytes *= 100; - baselen = 2; /* digit, prefix */ + baselen += 1; /* digit */ } if (flags & HN_NOSPACE) sep = ""; @@ -110,7 +132,7 @@ humanize_number(char *buf, size_t len, int64_t bytes, if (scale & (HN_AUTOSCALE | HN_GETSCALE)) { /* See if there is additional columns can be used. */ - for (max = 100, i = len - baselen; i-- > 0;) + for (max = 1, i = len - baselen; i-- > 0;) max *= 10; /* @@ -118,29 +140,38 @@ humanize_number(char *buf, size_t len, int64_t bytes, * If there will be an overflow by the rounding below, * divide once more. */ - for (i = 0; bytes >= max - 50 && i < maxscale; i++) - bytes /= divisor; + for (i = 0; + (quotient >= max || (quotient == max - 1 && + remainder >= divisordeccut)) && i < maxscale; i++) { + remainder = quotient % divisor; + quotient /= divisor; + } if (scale & HN_GETSCALE) return (i); - } else - for (i = 0; i < scale && i < maxscale; i++) - bytes /= divisor; + } else { + for (i = 0; i < scale && i < maxscale; i++) { + remainder = quotient % divisor; + quotient /= divisor; + } + } /* If a value <= 9.9 after rounding and ... */ - if (bytes < 995 && i > 0 && flags & HN_DECIMAL) { - /* baselen + \0 + .N */ - if (len < baselen + 1 + 2) - return (-1); - b = ((int)bytes + 5) / 10; - s1 = b / 10; - s2 = b % 10; + /* + * XXX - should we make sure there is enough space for the decimal + * place and if not, don't do HN_DECIMAL? + */ + if (((quotient == 9 && remainder < divisordeccut) || quotient < 9) && + i > 0 && flags & HN_DECIMAL) { + s1 = (int)quotient + ((remainder * 10 + divisor / 2) / + divisor / 10); + s2 = ((remainder * 10 + divisor / 2) / divisor) % 10; r = snprintf(buf, len, "%d%s%d%s%s%s", sign * s1, localeconv()->decimal_point, s2, sep, SCALE2PREFIX(i), suffix); } else r = snprintf(buf, len, "%" PRId64 "%s%s%s", - sign * ((bytes + 50) / 100), + sign * (quotient + (remainder + divisor / 2) / divisor), sep, SCALE2PREFIX(i), suffix); return (r); diff --git a/lib/libutil/humanize_unsigned.c b/lib/libutil/humanize_unsigned.c index cc788fc0b0..17e75a1af9 100644 --- a/lib/libutil/humanize_unsigned.c +++ b/lib/libutil/humanize_unsigned.c @@ -31,8 +31,7 @@ #include #include - -#include "libutil.h" +#include /* * snprintf() `bytes' into `buf', reformatting it so that the number, diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h index ad74a26440..bbf1904a95 100644 --- a/lib/libutil/libutil.h +++ b/lib/libutil/libutil.h @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/lib/libutil/libutil.h 247919 2013-03-07 19:00:00Z db $ */ #ifndef _LIBUTIL_H_ @@ -58,6 +58,7 @@ typedef struct _property { /* Avoid pulling in all the include files for no need. */ struct in_addr; +struct pidfh; struct sockaddr; struct termios; struct winsize; @@ -65,7 +66,7 @@ struct utmp; struct utmpx; __BEGIN_DECLS -int flopen(const char *, int, ...); +char *auth_getval(const char *_name); void login(struct utmp *); void loginx(const struct utmpx *); int login_tty(int); @@ -74,11 +75,14 @@ int logoutx(const char *, int, int); void logwtmp(const char *, const char *, const char *); void logwtmpx(const char *, const char *, const char *, int, int); void trimdomain(char *, int); -int openpty(int *, int *, char *, struct termios *, struct winsize *); -int forkpty(int *, char *, struct termios *, struct winsize *); +int expand_number(const char *_buf, uint64_t *_num); +int flopen(const char *_path, int _flags, ...); +int forkpty(int *_amaster, char *_name, + struct termios *_termp, struct winsize *_winp); int dehumanize_number(const char *, int64_t *); void hexdump(const void *_ptr, int _length, const char *_hdr, int _flags); -int humanize_number(char *, size_t, int64_t, const char *, int, int); +int humanize_number(char *_buf, size_t _len, int64_t _number, + const char *_suffix, int _scale, int _flags); int humanize_unsigned(char *buf, size_t len, uint64_t bytes, const char *suffix, int divisor); int format_bytes(char *buf, size_t len, uint64_t bytes); @@ -87,11 +91,18 @@ int uu_lock(const char *); int uu_unlock(const char *); int uu_lock_txfr(const char *, pid_t); int _secure_path(const char *, uid_t, gid_t); -int pidfile(const char *); -properties properties_read(int fd); -void properties_free(properties); -char *property_find(properties, const char *); -char *auth_getval(const char *); +int openpty(int *_amaster, int *_aslave, char *_name, + struct termios *_termp, struct winsize *_winp); +int pidfile_close(struct pidfh *_pfh); +int pidfile_fileno(const struct pidfh *_pfh); +struct pidfh * + pidfile_open(const char *_path, mode_t _mode, pid_t *_pidptr); +int pidfile_remove(struct pidfh *_pfh); +int pidfile_write(struct pidfh *_pfh); +void properties_free(properties _list); +char *property_find(properties _list, const char *_name); +properties + properties_read(int fd); int realhostname(char *, size_t, const struct in_addr *); int realhostname_sa(char *, size_t, struct sockaddr *, int); #ifdef _STDIO_H_ /* avoid adding new includes */ @@ -108,6 +119,7 @@ int pw_equal(const struct passwd *_pw1, const struct passwd *_pw2); void pw_fini(void); int pw_init(const char *_dir, const char *_master); char *pw_make(const struct passwd *_pw); +char *pw_make_v7(const struct passwd *_pw); int pw_mkdb(const char *_user); int pw_lock(void); struct passwd * @@ -122,6 +134,8 @@ int gr_copy(int __ffd, int _tfd, const struct group *_gr, struct group *_old_gr); struct group * gr_dup(const struct group *_gr); +struct group * + gr_add(const struct group *_gr, const char *_newmember); int gr_equal(const struct group *_gr1, const struct group *_gr2); void gr_fini(void); int gr_init(const char *_dir, const char *_master); diff --git a/lib/libutil/login.c b/lib/libutil/login.c index 3c743a69e4..3b65e637f8 100644 --- a/lib/libutil/login.c +++ b/lib/libutil/login.c @@ -28,7 +28,6 @@ * * @(#)login.c 8.1 (Berkeley) 6/4/93 * $FreeBSD: src/lib/libutil/login.c,v 1.6 1999/08/28 00:05:45 peter Exp $ - * $DragonFly: src/lib/libutil/login.c,v 1.6 2007/12/30 13:44:33 matthias Exp $ */ #include @@ -37,8 +36,7 @@ #include #include #include - -#include "libutil.h" +#include void login(struct utmp *ut) diff --git a/lib/libutil/login.conf.5 b/lib/libutil/login.conf.5 index 1babffdb36..a303d00e2f 100644 --- a/lib/libutil/login.conf.5 +++ b/lib/libutil/login.conf.5 @@ -17,7 +17,7 @@ .\" 5. Modifications may be freely made to this file providing the above .\" conditions are met. .\" -.\" $FreeBSD: src/lib/libutil/login.conf.5,v 1.22.2.18 2003/05/10 23:30:54 murray Exp $ +.\" $FreeBSD: head/lib/libutil/login.conf.5 257205 2013-10-27 04:59:18Z eadler $ .\" .Dd January 21, 2012 .Dt LOGIN.CONF 5 @@ -39,6 +39,8 @@ It is used by various programs in the system to set up a user's login environment and to enforce policy, accounting and administrative restrictions. It also provides the means by which users are able to be authenticated to the system and the types of authentication available. +Attributes in addition to the ones described here are available with +third-party packages. .Pp A special record "default" in the system user class capability database .Pa /etc/login.conf @@ -48,9 +50,7 @@ non-root user without a valid login class in A user with a uid of 0 without a valid login class will use the record "root" if it exists, or "default" if not. .Pp -In -.Dx , -users may individually create a file called +Users may individually create a file called .Pa .login_conf in their home directory using the same format, consisting of a single entry with a record id of "me". @@ -72,6 +72,28 @@ All names but the last should be in lower case and contain no blanks; the last name may contain upper case characters and blanks for readability. .Pp +Note that since a colon +.Pq Ql :\& +is used to separate capability entries, a +.Ql \ec +escape sequence must be used to embed a literal colon in the +value or name of a capability. +.Pp +The default +.Pa /etc/login.conf +shipped with +.Fx +is an out of the box configuration. +Whenever changes to this, or +the user's +.Pa ~/.login_conf , +file are made, the modifications will not be picked up until +.Xr cap_mkdb 1 +is used to compile the file into a database. +This database file will have a +.Pa .db +extension and is accessed through +.Xr cgetent 3 . See .Xr getcap 3 for a more in-depth description of the format of a capability database. @@ -103,11 +125,12 @@ home directories etc.) A numeric value, either decimal (default), hexadecimal (with leading 0x), or octal (with a leading 0). With a numeric type, only one numeric value is allowed. -Numeric types may also be specified in string format (ie. the capability +Numeric types may also be specified in string format (i.e., the capability tag being delimited from the value by '=' instead of '#'). Whichever method is used, then all records in the database must use the same method to allow values to be correctly overridden in interpolated records. +A numeric value may be infinite. .It size A number which expresses a size. The default interpretation of a value is the number of bytes, but a @@ -126,6 +149,7 @@ represents terabytes. .El A size value is a numeric quantity and case of the suffix is not significant. Concatenated values are added together. +A size value may be infinite. .It time A period of time, by default in seconds. A prefix may specify a different unit: @@ -146,26 +170,34 @@ the number of seconds. Concatenated values are added together. For example, 2 hours and 40 minutes may be written either as 9600s, 160m or 2h40m. +A time value may be infinite. .El .Pp +.Dq infinity , +.Dq inf , +.Dq unlimited , +.Dq unlimit, +and -1 +are considered infinite values. +.Pp The usual convention to interpolate capability entries using the special .Em tc=value notation may be used. .Sh RESOURCE LIMITS .Bl -column coredumpsize indent indent -.It Sy Name Ta Sy Type Ta Sy Notes Ta Sy Description -.It coredumpsize size Maximum coredump size limit. -.It cputime time CPU usage limit. -.It datasize size Maximum data size limit. -.It filesize size Maximum file size limit. -.It maxproc number Maximum number of processes. -.It memorylocked size Maximum locked in core memory size limit. -.It memoryuse size Maximum of core memory use size limit. -.It openfiles number Maximum number of open files per process. -.It sbsize size Maximum permitted socketbuffer size. -.It vmemoryuse size Maximum permitted total VM usage per process. -.It stacksize size Maximum stack size limit. -.It posixlocks size Maximum number of POSIX-type advisory-mode locks. +.It Sy "Name Type Notes Description" +.It "coredumpsize size Maximum coredump size limit." +.It "cputime time CPU usage limit." +.It "datasize size Maximum data size limit." +.It "filesize size Maximum file size limit." +.It "maxproc number Maximum number of processes." +.It "memorylocked size Maximum locked in core memory size limit." +.It "memoryuse size Maximum of core memory use size limit." +.It "openfiles number Maximum number of open files per process." +.It "sbsize size Maximum permitted socketbuffer size." +.It "vmemoryuse size Maximum permitted total VM usage per process." +.It "stacksize size Maximum stack size limit." +.It "posixlocks size Maximum number of POSIX-type advisory-mode locks." .El .Pp These resource limit entries actually specify both the maximum @@ -177,41 +209,42 @@ The maximum and current limits may be specified individually by appending a -max or -cur to the capability name. .Sh ENVIRONMENT .Bl -column ignorenologin indent xbinxxusrxbin -.It Sy Name Ta Sy Type Ta Sy Notes Ta Sy Description -.It charset string Set $MM_CHARSET environment variable to the specified +.It Sy "Name Type Notes Description" +.It "charset string Set $MM_CHARSET environment variable to the specified" value. -.It hushlogin bool false Same as having a ~/.hushlogin file. -.It ignorenologin bool false Login not prevented by nologin. -.It lang string Set $LANG environment variable to the specified value. -.It manpath path Default search path for manpages. -.It nologin file If the file exists it will be displayed and +.It "hushlogin bool false Same as having a ~/.hushlogin file." +.It "ignorenologin bool false Login not prevented by nologin." +.It "lang string Set $LANG environment variable to the specified value." +.It "manpath path Default search path for manpages." +.It "nocheckmail bool false Display mail status at login." +.It "nologin file If the file exists it will be displayed and" the login session will be terminated. -.It path path /bin /usr/bin Default search path. -.It priority number Initial priority (nice) level. -.It requirehome bool false Require a valid home directory to login. -.It setenv list A comma-separated list of environment variables and +.It "path path /bin /usr/bin Default search path." +.It "priority number Initial priority (nice) level." +.It "requirehome bool false Require a valid home directory to login." +.It "setenv list A comma-separated list of environment variables and" values to which they are to be set. -.It shell prog Session shell to execute rather than the +.It "shell prog Session shell to execute rather than the" shell specified in the passwd file. The SHELL environment variable will contain the shell specified in the password file. -.It term string Default terminal type if not able to determine +.It "term string Default terminal type if not able to determine" from other means. -.It timezone string Default value of $TZ environment variable. -.It umask number 022 Initial umask. Should always have a leading 0 to +.It "timezone string Default value of $TZ environment variable." +.It "umask number 022 Initial umask. Should always have a leading 0 to" ensure octal interpretation. -.It welcome file /etc/motd File containing welcome message. +.It "welcome file /etc/motd File containing welcome message." .El .Sh AUTHENTICATION .Bl -column minpasswordlen indent indent -.It Sy Name Ta Sy Type Ta Sy Notes Ta Sy Description -.\" .It approve program Program to approve login. -.It copyright file File containing additional copyright information -.It host.allow list List of remote host wildcards from which users in +.It Sy "Name Type Notes Description" +.\" .It "approve program Program to approve login. +.It "copyright file File containing additional copyright information" +.It "host.allow list List of remote host wildcards from which users in" the class may access. -.It host.deny list List of remote host wildcards from which users +.It "host.deny list List of remote host wildcards from which users" in the class may not access. -.It login_prompt string The login prompt given by +.It "login_prompt string The login prompt given by" .Xr login 1 .It minpasswordlen number 6 The minimum length a local password may be. @@ -221,27 +254,27 @@ will warn the user if an all lower case password is entered. .It login-backoff number 3 The number of login attempts allowed before the backoff delay is inserted after each subsequent attempt. -.It login-retries number 10 The number of login attempts +.It "login-retries number 10 The number of login attempts" allowed before the login fails. -.It passwd_format string sha512 The encryption format that new or +.It "passwd_format string sha512 The encryption format that new or" changed passwords will use. -Valid values include "des", "md5", "blf", "sha256" and "sha512". -See -.Xr crypt 3 . +Valid values include "des", "md5", "blf", "sha256" and "sha512"; see +.Xr crypt 3 +for details. NIS clients using a .No non- Ns Dx Ns / Ns Fx NIS server should probably use "des". -.It passwd_prompt string The password prompt presented by +.It "passwd_prompt string The password prompt presented by" .Xr login 1 -.It times.allow list List of time periods during which +.It "times.allow list List of time periods during which" logins are allowed. -.It times.deny list List of time periods during which logins are +.It "times.deny list List of time periods during which logins are" disallowed. -.It ttys.allow list List of ttys and ttygroups which users +.It "ttys.allow list List of ttys and ttygroups which users" in the class may use for access. -.It ttys.deny list List of ttys and ttygroups which users +.It "ttys.deny list List of ttys and ttygroups which users" in the class may not use for access. -.\".It widepasswords bool false Use the wide password format. The wide password +.\".It "widepasswords bool false Use the wide password format. The wide password .\" format allows up to 128 significant characters in the password. .El .Pp @@ -331,33 +364,33 @@ If both lists are given and are non-empty, the user is restricted to those devices allowed by ttys.allow that are not available by ttys.deny. .Sh ACCOUNTING LIMITS .Bl -column host.accounted indent indent -.It Sy Name Ta Sy Type Ta Sy Notes Ta Sy Description -.It accounted bool false Enable session time accounting for all users +.It Sy "Name Type Notes Description" +.It "accounted bool false Enable session time accounting for all users" in this class. -.It autodelete time Time after expiry when account is auto-deleted. -.It bootfull bool false Enable 'boot only if ttygroup is full' strategy +.It "autodelete time Time after expiry when account is auto-deleted." +.It "bootfull bool false Enable 'boot only if ttygroup is full' strategy" when terminating sessions. -.It daytime time Maximum login time per day. -.It expireperiod time Time for expiry allocation. -.It graceexpire time Grace days for expired account. -.It gracetime time Additional grace login time allowed. -.It host.accounted list List of remote host wildcards from which +.It "daytime time Maximum login time per day." +.It "expireperiod time Time for expiry allocation." +.It "graceexpire time Grace days for expired account." +.It "gracetime time Additional grace login time allowed." +.It "host.accounted list List of remote host wildcards from which" login sessions will be accounted. -.It host.exempt list List of remote host wildcards from which +.It "host.exempt list List of remote host wildcards from which" login session accounting is exempted. .It idletime time Maximum idle time before logout (unused). .It monthtime time Maximum login time per month. .It passwordtime time Used by .Xr passwd 1 to set next password expiry date. -.It refreshtime time New time allowed on account refresh. -.It refreshperiod str How often account time is refreshed. -.It sessiontime time Maximum login time per session. -.It sessionlimit number Maximum number of concurrent +.It "refreshtime time New time allowed on account refresh." +.It "refreshperiod str How often account time is refreshed." +.It "sessiontime time Maximum login time per session." +.It "sessionlimit number Maximum number of concurrent" login sessions on ttys in any group. -.It ttys.accounted list List of ttys and ttygroups for which +.It "ttys.accounted list List of ttys and ttygroups for which" login accounting is active. -.It ttys.exempt list List of ttys and ttygroups for which login accounting +.It "ttys.exempt list List of ttys and ttygroups for which login accounting" is exempt. .It warnexpire time Advance notice for pending account expiry. .It warnpassword time Advance notice for pending password expiry. diff --git a/lib/libutil/login_auth.3 b/lib/libutil/login_auth.3 index 9cc28f9a05..e4383b9a93 100644 --- a/lib/libutil/login_auth.3 +++ b/lib/libutil/login_auth.3 @@ -17,7 +17,7 @@ .\" 5. Modifications may be freely made to this file providing the above .\" conditions are met. .\" -.\" $FreeBSD: src/lib/libutil/login_auth.3,v 1.9.2.4 2001/12/17 10:08:32 ru Exp $ +.\" $FreeBSD: head/lib/libutil/login_auth.3 206622 2010-04-14 19:08:06Z uqs $ .\" .Dd December 29, 1996 .Dt LOGIN_AUTH 3 diff --git a/lib/libutil/login_auth.c b/lib/libutil/login_auth.c index 74df3e7d97..8f9813a2bf 100644 --- a/lib/libutil/login_auth.c +++ b/lib/libutil/login_auth.c @@ -25,20 +25,18 @@ * * Low-level routines relating to the user capabilities database * - * $FreeBSD: src/lib/libutil/login_auth.c,v 1.11 1999/08/28 00:05:45 peter Exp $ - * $DragonFly: src/lib/libutil/login_auth.c,v 1.3 2005/03/04 04:31:11 cpressey Exp $ + * $FreeBSD: head/lib/libutil/login_auth.c 255007 2013-08-28 21:10:37Z jilles $ */ #include #include +#include #include #include #include #include -#include "login_cap.h" - /* * auth_checknologin() @@ -52,7 +50,7 @@ void auth_checknologin(login_cap_t *lc) { - char *file; + const char *file; /* Do we ignore a nologin file? */ if (login_getcapbool(lc, "ignorenologin", 0)) @@ -85,7 +83,7 @@ auth_cat(const char *file) int fd, count; char buf[BUFSIZ]; - if ((fd = open(file, O_RDONLY)) < 0) + if ((fd = open(file, O_RDONLY | O_CLOEXEC)) < 0) return 0; while ((count = read(fd, buf, sizeof(buf))) > 0) (void)write(fileno(stdout), buf, count); diff --git a/lib/libutil/login_cap.3 b/lib/libutil/login_cap.3 index a840790705..4a9d5dd655 100644 --- a/lib/libutil/login_cap.3 +++ b/lib/libutil/login_cap.3 @@ -17,9 +17,9 @@ .\" 5. Modifications may be freely made to this file providing the above .\" conditions are met. .\" -.\" $FreeBSD: src/lib/libutil/login_cap.3,v 1.17.2.8 2002/12/29 16:35:36 schweikh Exp $ +.\" $FreeBSD: head/lib/libutil/login_cap.3 233648 2012-03-29 05:02:12Z eadler $ .\" -.Dd December 27, 1996 +.Dd June 14, 2007 .Dt LOGIN_CAP 3 .Os .Sh NAME @@ -52,12 +52,12 @@ .Fn login_getpwclass "const struct passwd *pwd" .Ft login_cap_t * .Fn login_getuserclass "const struct passwd *pwd" -.Ft char * -.Fn login_getcapstr "login_cap_t *lc" "const char *cap" "char *def" "char *error" -.Ft char ** +.Ft "const char *" +.Fn login_getcapstr "login_cap_t *lc" "const char *cap" "const char *def" "const char *error" +.Ft "const char **" .Fn login_getcaplist "login_cap_t *lc" "const char *cap" "const char *chars" -.Ft char * -.Fn login_getpath "login_cap_t *lc" "const char *cap" "char *error" +.Ft "const char *" +.Fn login_getpath "login_cap_t *lc" "const char *cap" "const char *error" .Ft rlim_t .Fn login_getcaptime "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error" .Ft rlim_t @@ -66,8 +66,8 @@ .Fn login_getcapsize "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error" .Ft int .Fn login_getcapbool "login_cap_t *lc" "const char *cap" "int def" -.Ft char * -.Fn login_getstyle "login_cap_t *lc" "char *style" "const char *auth" +.Ft "const char *" +.Fn login_getstyle "login_cap_t *lc" "const char *style" "const char *auth" .Ft const char * .Fn login_setcryptfmt "login_cap_t *lc" "const char *def" "const char *error" .Sh DESCRIPTION @@ -85,8 +85,11 @@ consist of colon .Ql \&: separated fields, the first field in each record being one or more identifiers for the record (which must be unique for the entire database), -each separated by a '|', and may optionally include a description as -the last 'name'. +each separated by a +.Ql | , +and may optionally include a description as +the last +.Sq name . Remaining fields in the record consist of keyword/data pairs. Long lines may be continued with a backslash within empty entries, with the second and subsequent lines optionally indented for readability. @@ -95,9 +98,13 @@ This is similar to the format used in except that keywords are not limited to two significant characters, and are usually longer for improved readability. As with termcap entries, multiple records can be linked together -(one record including another) using a field containing tc=. -The result is that the entire record referenced by replaces -the tc= field at the point at which it occurs. +(one record including another) using a field containing +.Ql tc= Ns Va . +The result is that the entire record referenced by +.Va +replaces the +.Va tc= +field at the point at which it occurs. See .Xr getcap 3 for further details on the format and use of a capabilities database. @@ -105,7 +112,9 @@ for further details on the format and use of a capabilities database. The .Nm login_cap interface provides a convenient means of retrieving login class -records with all tc= references expanded. +records with all +.Va tc= +references expanded. A program will typically call one of .Fn login_getclass , .Fn login_getpwclass , @@ -114,14 +123,18 @@ or .Fn login_getclassbyname according to its requirements. Each of these functions returns a login capabilities structure, -.Ft login_cap_t , +.Vt login_cap_t , which may subsequently be used to interrogate the database for specific values using the rest of the API. -Once the login_cap_t is of no further use, the +Once the +.Vt login_cap_t +is of no further use, the .Fn login_close function should be called to free all resources used. .Pp -The structure of login_cap_t is defined in +The structure of +.Vt login_cap_t +is defined in .In login_cap.h , as: .Bd -literal -offset indent @@ -133,106 +146,165 @@ typedef struct { .Ed .Pp The -.Ar lc_class +.Fa lc_class member contains a pointer to the name of the login class retrieved. This may not necessarily be the same as the one requested, either directly via .Fn login_getclassbyname , -indirectly via a user's login record using +or indirectly via a user's login record using .Fn login_getpwclass , by class name using -.Fn login_getclass , -or -.Fn login_getuserclass . +.Fn login_getclass . If the referenced user has no login class specified in .Pa /etc/master.passwd , -the class name is NULL or an empty string. +the class name is +.Dv NULL +or an empty string. If the class specified does not exist in the database, each of these -functions will search for a record with an id of "default", +functions will search for a record with an id of +.Ql default , with that name returned in the -.Ar lc_class +.Fa lc_class field. In addition, if the referenced user has a UID of 0 (normally, -"root", although the user name is not considered) then +.Ql root , +although the user name is not considered) then .Fn login_getpwclass -will search for a record with an id of "root" before it searches -for the record with the id of "default". +will search for a record with an id of +.Ql root +before it searches +for the record with the id of +.Ql default . .Pp The -.Ar lc_cap +.Fa lc_cap field is used internally by the library to contain the expanded login capabilities record. Programs with unusual requirements may wish to use this with the lower-level -.Xr getcap 3 +.Fn getcap style functions to access the record directly. .Pp The -.Ar lc_style +.Fa lc_style field is set by the .Fn login_getstyle function to the authorisation style, according to the requirements of the program handling a login itself. .Pp -As noted above, the -.Fn login_get*class -functions return a login_cap_t object which is used to access -the matching or default record in the capabilities database. +The .Fn login_getclassbyname -accepts two arguments: the first one is the record identifier of the -record to be retrieved, the second is an optional directory name. -If the first -.Ar name -argument is NULL, an empty string, or a class that does not exist -in the supplemental or system login class database, then the system -.Em default -record is returned instead. -If the second -.Ar dir -parameter is NULL, then only the system login class database is -used, but when not NULL, the named directory is searched for -a login database file called ".login_conf", and capability records -contained within it may override the system defaults. -This scheme allows users to override some login settings from -those in the system login class database by creating class records -for their own private class with a record id of `me'. -In the context of a -.Em login , -it should be noted that some options cannot by overridden by -users for two reasons; many options, such as resource settings -and default process priorities, require root privileges -in order to take effect, and other fields in the user's file are -not be consulted at all during the early phases of login for -security or administrative reasons. -See -.Xr login.conf 5 -for more information on which settings a user is able to override. -Typically, these are limited purely to the user's default login -environment which might otherwise have been overridden in shell -startup scripts in any case. -The user's +function is the basic means to get a +.Vt login_cap_t +object. +It accepts two arguments: the first one, +.Fa name , +is the record identifier of the +record to be retrieved; the second, +.Fa pwd , +is an optional pointer to a +.Vt passwd +structure. +First of all, its arguments are used by the function +to choose between system and user modes of operation. +When in system mode, only the system login class database is used. +When in user mode, the supplemental login class database in the +user's home directory is allowed to override settings from the system +database in a limited way as noted below. +To minimize security implications, user mode is entered by +.Fn login_getclassbyname +if and only if +.Fa name +is +.Dv LOGIN_MECLASS +.Pq Ql me +and +.Fa pwd +is not +.Dv NULL . +Otherwise system mode is chosen. +.Pp +In system mode, any record in the system database +.Pa /etc/login.conf +can be accessed, +and a fallback to the default record is provided as follows. +If +.Fa name +is +.Dv NULL , +an empty string, or a class that does not exist +in the login class database, then the +.Dv LOGIN_DEFCLASS +record +.Pq Ql default +is returned instead. +.Pp +In user mode, only the +.Dv LOGIN_MECLASS +record +.Pq Ql me +is accessed and no fallback to the +.Ql default +record is provided. +The directory specified by +.Fa pwd->pw_dir +is searched for +a login database file called +.Pa .login_conf , +and only the +.Ql me +capability record +contained within it may override the system record with the same name +while other records are ignored. +Using this scheme, an application can explicitly +allow users to override a selected subset of login settings. +To do so, the application should obtain two +.Vt login_cap_t +objects, one in user mode and the other in system mode, +and then query the user object before the +system object for login parameters that are allowed to +be overridden by the user. +For example, the user's .Pa .login_conf -merely provides a convenient way for a user to set up their preferred -login environment before the shell is invoked on login. +can provide a convenient way for a user to set up their preferred +login environment before the shell is invoked on login if supported by +.Xr login 1 . .Pp -If the specified record is NULL, empty or does not exist, and the -system has no "default" record available to fall back to, there is a +Note that access to the +.Pa /etc/login.conf +and +.Pa .login_conf +files will only be performed subject to the security checks documented in +.Xr _secure_path 3 +for the uids 0 and +.Fa pwd->pw_uid +respectively. +.Pp +If the specified record is +.Dv NULL , +empty or does not exist, and the +system has no +.Ql default +record available to fall back to, there is a memory allocation error or for some reason .Xr cgetent 3 is unable to access the login capabilities database, this function -returns NULL. +returns +.Dv NULL . .Pp The functions -.Fn login_getpwclass , -.Fn login_getclass +.Fn login_getclass , +.Fn login_getpwclass and .Fn login_getuserclass retrieve the applicable login class record for the user's passwd entry or class name by calling .Fn login_getclassbyname . -On failure, NULL is returned. +On failure, +.Dv NULL +is returned. The difference between these functions is that .Fn login_getuserclass includes the user's overriding @@ -245,22 +317,42 @@ restrict lookup only to the system login class database in .Pa /etc/login.conf . As explained earlier, .Fn login_getpwclass -only differs from +differs from .Fn login_getclass -in that it allows the default class for user 'root' as "root" +in that it allows the default class for a super-user as +.Ql root if none has been specified in the password database. -Otherwise, if the passwd pointer is NULL, or the user record -has no login class, then the system "default" entry is retrieved. +Otherwise, if the passwd pointer is +.Dv NULL , +or the user record +has no login class, then the system +.Ql default +entry is retrieved. +Essentially, +.Fn login_getclass name +is equivalent to +.Fn login_getclassbyname name NULL +and +.Fn login_getuserclass pwd +to +.Fn login_getclassbyname LOGIN_MECLASS pwd . .Pp -Once a program no longer wishes to use a login_cap_t object, +Once a program no longer wishes to use a +.Vt login_cap_t +object, .Fn login_close may be called to free all resources used by the login class. +The .Fn login_close -may be passed a NULL pointer with no harmful side-effects. +function may be passed a +.Dv NULL +pointer with no harmful side-effects. .Pp The remaining functions may be used to retrieve individual capability records. -Each function takes a login_cap_t object as its first parameter, +Each function takes a +.Vt login_cap_t +object as its first parameter, a capability tag as the second, and remaining parameters being default and error values that are returned if the capability is not found. @@ -281,21 +373,22 @@ Memory allocated during retrieval or processing of capability tags is automatically reused by subsequent calls to functions in this group, or deallocated on calling .Fn login_close . -.Bl -tag -width ".Fn login_setcryptfmt" +.Bl -tag -width "login_getcaplist()" .It Fn login_getcapstr This function returns a simple string capability. If the string is not found, then the value in -.Ar def +.Fa def is returned as the default value, or if an error occurs, the value in the -.Ar error +.Fa error parameter is returned. .It Fn login_getcaplist This function returns the value corresponding to the named -capability tag as a list of values in a NULL terminated -array. +capability tag as a list of values in a +.Dv NULL +terminated array. Within the login class database, some tags are of type -.Em list , +.Vt list , which consist of one or more comma- or space separated values. Usually, this function is not called directly from an @@ -303,57 +396,91 @@ application, but is used indirectly via .Fn login_getstyle . .It Fn login_getpath This function returns a list of directories separated by colons -.Ql &: . +.Ql \&: . Capability tags for which this function is called consist of a list of directories separated by spaces. .It Fn login_getcaptime This function returns a -.Em time value +.Vt time value associated with a particular capability tag with the value expressed in seconds (the default), minutes, hours, days, weeks or (365 day) years or any combination of these. -A suffix determines the units used: S for seconds, M for minutes, -H for hours, D for days, W for weeks and Y for 365 day years. +A suffix determines the units used: +.Ql S +for seconds, +.Ql M +for minutes, +.Ql H +for hours, +.Ql D +for days, +.Ql W +for weeks and +.Ql Y +for 365 day years. Case of the units suffix is ignored. .Pp Time values are normally used for setting resource, accounting and session limits. If supported by the operating system and compiler (which is true of -.Dx ) , -the value returned is a quad (long long), of type -.Em rlim_t . -A value "inf" or "infinity" may be used to express an infinite -value, in which case RLIM_INFINITY is returned. +.Fx ) , +the value returned is a +.Vt quad +.Pq Vt long long , +of type +.Vt rlim_t . +A value +.Ql inf +or +.Ql infinity +may be used to express an infinite +value, in which case +.Dv RLIM_INFINITY +is returned. .It Fn login_getcapnum This function returns a numeric value for a tag, expressed either as -tag= or the standard +.Ql tag= +or the standard .Fn cgetnum -format tag#. +format +.Ql tag# . The first format should be used in preference to the second, the second format is provided for compatibility and consistency with the .Xr getcap 3 database format where numeric types use the .Ql \&# as the delimiter for numeric values. -If in the first format, then the value given may be "inf" or -"infinity" which results in a return value of RLIM_INFINITY. +If in the first format, then the value given may be +.Ql inf +or +.Ql infinity +which results in a return value of +.Dv RLIM_INFINITY . If the given capability tag cannot be found, the -.Ar def +.Fa def parameter is returned, and if an error occurs, the -.Ar error +.Fa error parameter is returned. .It Fn login_getcapsize .Fn login_getcapsize returns a value representing a size (typically, file or memory) which may be expressed as bytes (the default), 512 byte blocks, kilobytes, megabytes, gigabytes, and on systems that support the -.Ar long long +.Vt long long type, terabytes. The suffix used determines the units, and multiple values and -units may be used in combination (e.g. 1m500k = 1.5 megabytes). -A value with no suffix is interpreted as bytes, B as 512-byte -blocks, K as kilobytes, M as megabytes, G as gigabytes and T as -terabytes. +units may be used in combination (e.g.\& 1m500k = 1.5 megabytes). +A value with no suffix is interpreted as bytes, +.Ql B +as 512-byte blocks, +.Ql K +as kilobytes, +.Ql M +as megabytes, +.Ql G +as gigabytes and +.Ql T +as terabytes. Case is ignored. The error value is returned if there is a login capabilities database error, if an invalid suffix is used, or if a numeric value cannot be @@ -361,33 +488,61 @@ interpreted. .It Fn login_getcapbool This function returns a boolean value tied to a particular flag. It returns 0 if the given capability tag is not present or is -negated by the presence of a "tag@" (See +negated by the presence of a +.Ql tag@ +(see .Xr getcap 3 for more information on boolean flags), and returns 1 if the tag is found. .It Fn login_getstyle This function is used by the login authorisation system to determine the style of login available in a particular case. -The function accepts three parameters, the login_cap entry itself and -two optional parameters, and authorisation type 'auth' and 'style', and +The function accepts three parameters, the +.Fa lc +entry itself and +two optional parameters, and authorisation type +.Fa auth +and +.Fa style , +and applies these to determine the authorisation style that best suites these rules. .Bl -bullet .It -If 'auth' is neither NULL nor an empty string, look for a tag of type -"auth-" in the capability record. -If not present, then look for the default tag "auth=". +If +.Fa auth +is neither +.Dv NULL +nor an empty string, look for a tag of type +.Ql auth- Ns Fa +in the capability record. +If not present, then look for the default tag +.Va auth= . .It If no valid authorisation list was found from the previous step, then -default to "passwd" as the authorisation list. +default to +.Ql passwd +as the authorisation list. .It -If 'style' is not NULL or empty, look for it in the list of authorisation -methods found from the pprevious step. -If 'style' is NULL or an empty string, then default to "passwd" +If +.Fa style +is not +.Dv NULL +or empty, look for it in the list of authorisation +methods found from the previous step. +If +.Fa style +is +.Dv NULL +or an empty string, then default to +.Ql passwd authorisation. .It -If 'style' is found in the chosen list of authorisation methods, then -return that, otherwise return NULL. +If +.Fa style +is found in the chosen list of authorisation methods, then +return that, otherwise return +.Dv NULL . .El .Pp This scheme allows the administrator to determine the types of @@ -404,7 +559,7 @@ The function is used to set the .Xr crypt 3 format using the -.Ql passwd_format +.Va passwd_format configuration entry. If no entry is found, .Fa def @@ -416,6 +571,7 @@ on the specifier fails, is returned to indicate this. .El .Sh SEE ALSO +.Xr login 1 , .Xr crypt 3 , .Xr getcap 3 , .Xr login_class 3 , diff --git a/lib/libutil/login_cap.c b/lib/libutil/login_cap.c index 4bc609f597..5903fc0e39 100644 --- a/lib/libutil/login_cap.c +++ b/lib/libutil/login_cap.c @@ -25,17 +25,17 @@ * * Low-level routines relating to the user capabilities database * - * $FreeBSD: src/lib/libutil/login_cap.c,v 1.17.2.4 2001/10/21 19:42:13 ache Exp $ - * $DragonFly: src/lib/libutil/login_cap.c,v 1.4 2008/10/29 22:03:12 swildner Exp $ + * $FreeBSD: head/lib/libutil/login_cap.c 255007 2013-08-28 21:10:37Z jilles $ */ #include #include #include #include - #include #include +#include +#include #include #include #include @@ -43,9 +43,6 @@ #include #include -#include "libutil.h" -#include "login_cap.h" - /* * allocstr() * Manage a single static pointer for handling a local char* buffer, @@ -61,10 +58,12 @@ static int lc_object_count = 0; static size_t internal_stringsz = 0; static char * internal_string = NULL; static size_t internal_arraysz = 0; -static char ** internal_array = NULL; +static const char ** internal_array = NULL; + +static char path_login_conf[] = _PATH_LOGIN_CONF; static char * -allocstr(char *str) +allocstr(const char *str) { char *p; @@ -79,10 +78,10 @@ allocstr(char *str) } -static char ** +static const char ** allocarray(size_t sz) { - char **p; + static const char **p; if (sz <= internal_arraysz) p = internal_array; @@ -102,25 +101,26 @@ allocarray(size_t sz) * Free using freearraystr() */ -static char ** -arrayize(char *str, const char *chars, int *size) +static const char ** +arrayize(const char *str, const char *chars, int *size) { int i; char *ptr; - char **res = NULL; + const char *cptr; + const char **res = NULL; /* count the sub-strings */ - for (i = 0, ptr = str; *ptr; i++) { - int count = strcspn(ptr, chars); - ptr += count; - if (*ptr) - ++ptr; + for (i = 0, cptr = str; *cptr; i++) { + int count = strcspn(cptr, chars); + cptr += count; + if (*cptr) + ++cptr; } /* alloc the array */ if ((ptr = allocstr(str)) != NULL) { if ((res = allocarray(++i)) == NULL) - free(str); + free((void *)(uintptr_t)(const void *)str); else { /* now split the string */ i = 0; @@ -170,12 +170,16 @@ login_close(login_cap_t * lc) /* - * login_getclassbyname() get the login class by its name. + * login_getclassbyname() + * Get the login class by its name. * If the name given is NULL or empty, the default class - * LOGIN_DEFCLASS (ie. "default") is fetched. If the - * 'dir' argument contains a non-NULL non-empty string, - * then the file _FILE_LOGIN_CONF is picked up from that - * directory instead of the system login database. + * LOGIN_DEFCLASS (i.e., "default") is fetched. + * If the name given is LOGIN_MECLASS and + * 'pwd' argument is non-NULL and contains an non-NULL + * dir entry, then the file _FILE_LOGIN_CONF is picked + * up from that directory and used before the system + * login database. In that case the system login database + * is looked up using LOGIN_MECLASS, too, which is a bug. * Return a filled-out login_cap_t structure, including * class name, and the capability record buffer. */ @@ -212,12 +216,14 @@ login_getclassbyname(char const *name, const struct passwd *pwd) if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir, _FILE_LOGIN_CONF) < MAXPATHLEN) { - login_dbarray[i] = userpath; if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1) - i++; /* only use 'secure' data */ + login_dbarray[i++] = userpath; } - if (_secure_path(_PATH_LOGIN_CONF, 0, 0) != -1) - login_dbarray[i++] = _PATH_LOGIN_CONF; + /* + * XXX: Why to add the system database if the class is `me'? + */ + if (_secure_path(path_login_conf, 0, 0) != -1) + login_dbarray[i++] = path_login_conf; login_dbarray[i] = NULL; memset(lc, 0, sizeof(login_cap_t)); @@ -226,13 +232,13 @@ login_getclassbyname(char const *name, const struct passwd *pwd) if (name == NULL || *name == '\0') name = LOGIN_DEFCLASS; - switch (cgetent(&lc->lc_cap, login_dbarray, (char*)name)) { + switch (cgetent(&lc->lc_cap, login_dbarray, name)) { case -1: /* Failed, entry does not exist */ if (me) break; /* Don't retry default on 'me' */ if (i == 0) r = -1; - else if ((r = open(login_dbarray[0], O_RDONLY)) >= 0) + else if ((r = open(login_dbarray[0], O_RDONLY | O_CLOEXEC)) >= 0) close(r); /* * If there's at least one login class database, @@ -244,9 +250,9 @@ login_getclassbyname(char const *name, const struct passwd *pwd) /* fall-back to default class */ name = LOGIN_DEFCLASS; msg = "%s: no default/fallback class '%s'"; - if (cgetent(&lc->lc_cap, login_dbarray, (char*)name) != 0 && r >= 0) + if (cgetent(&lc->lc_cap, login_dbarray, name) != 0 && r >= 0) break; - /* Fallthru - just return system defaults */ + /* FALLTHROUGH - just return system defaults */ case 0: /* success! */ if ((lc->lc_class = strdup(name)) != NULL) { if (dir) { @@ -300,12 +306,13 @@ login_getclass(const char *cls) /* - * login_getclass() + * login_getpwclass() * Get the login class for a given password entry from * the system (only) login class database. * If the password entry's class field is not set, or * the class specified does not exist, then use the - * default of LOGIN_DEFCLASS (ie. "default"). + * default of LOGIN_DEFCLASS (i.e., "default") for an unprivileged + * user or that of LOGIN_DEFROOTCLASS (i.e., "root") for a super-user. * Return a filled-out login_cap_t structure, including * class name, and the capability record buffer. */ @@ -320,14 +327,18 @@ login_getpwclass(const struct passwd *pwd) if (cls == NULL || *cls == '\0') cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; } + /* + * XXX: pwd should be unused by login_getclassbyname() unless cls is `me', + * so NULL can be passed instead of pwd for more safety. + */ return login_getclassbyname(cls, pwd); } /* * login_getuserclass() - * Get the login class for a given password entry, allowing user - * overrides via ~/.login_conf. + * Get the `me' login class, allowing user overrides via ~/.login_conf. + * Note that user overrides are allowed only in the `me' class. */ login_cap_t * @@ -337,16 +348,15 @@ login_getuserclass(const struct passwd *pwd) } - /* * login_getcapstr() * Given a login_cap entry, and a capability name, return the - * value defined for that capability, a defualt if not found, or + * value defined for that capability, a default if not found, or * an error string on error. */ -char * -login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error) +const char * +login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const char *error) { char *res; int ret; @@ -354,7 +364,7 @@ login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error) if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0') return def; - if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) + if ((ret = cgetstr(lc->lc_cap, cap, &res)) == -1) return def; return (ret >= 0) ? res : error; } @@ -367,14 +377,14 @@ login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error) * strings. */ -char ** +const char ** login_getcaplist(login_cap_t *lc, const char *cap, const char *chars) { - char *lstring; + const char *lstring; if (chars == NULL) chars = ", \t"; - if ((lstring = login_getcapstr(lc, (char*)cap, NULL, NULL)) != NULL) + if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL) return arrayize(lstring, chars, NULL); return NULL; } @@ -388,23 +398,23 @@ login_getcaplist(login_cap_t *lc, const char *cap, const char *chars) * If there is an error of any kind, return . */ -char * -login_getpath(login_cap_t *lc, const char *cap, char * error) +const char * +login_getpath(login_cap_t *lc, const char *cap, const char *error) { - char *str; - - if ((str = login_getcapstr(lc, (char*)cap, NULL, NULL)) == NULL) - str = error; - else { - char *ptr = str; + const char *str; + char *ptr; + int count; + str = login_getcapstr(lc, cap, NULL, NULL); + if (str == NULL) + return error; + ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */ while (*ptr) { - int count = strcspn(ptr, ", \t"); + count = strcspn(ptr, ", \t"); ptr += count; if (*ptr) *ptr++ = ':'; } - } return str; } @@ -537,7 +547,7 @@ login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) * If there's an error, return . */ - if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) + if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) return def; else if (r < 0) { errno = ERANGE; @@ -624,10 +634,10 @@ login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) /* * For BSDI compatibility, try for the tag= first */ - if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) { + if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) { long lval; /* string capability not present, so try for tag# as numeric */ - if ((r = cgetnum(lc->lc_cap, (char *)cap, &lval)) == -1) + if ((r = cgetnum(lc->lc_cap, cap, &lval)) == -1) return def; /* Not there, so return default */ else if (r >= 0) return (rlim_t)lval; @@ -673,7 +683,7 @@ login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) if (lc == NULL || lc->lc_cap == NULL) return def; - if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) + if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) return def; else if (r < 0) { errno = ERANGE; @@ -741,7 +751,7 @@ login_getcapbool(login_cap_t *lc, const char *cap, int def) { if (lc == NULL || lc->lc_cap == NULL) return def; - return (cgetcap(lc->lc_cap, (char *)cap, ':') != NULL); + return (cgetcap(lc->lc_cap, cap, ':') != NULL); } @@ -765,15 +775,15 @@ login_getcapbool(login_cap_t *lc, const char *cap, int def) * login_getstyle(lc, "skey", "network"); */ -char * -login_getstyle(login_cap_t *lc, char *style, const char *auth) +const char * +login_getstyle(login_cap_t *lc, const char *style, const char *auth) { int i; - char **authtypes = NULL; + const char **authtypes = NULL; char *auths= NULL; char realauth[64]; - static char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL }; + static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL }; if (auth != NULL && *auth != '\0') { if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)sizeof(realauth)) diff --git a/lib/libutil/login_cap.h b/lib/libutil/login_cap.h index 61366bbba9..a625e9d215 100644 --- a/lib/libutil/login_cap.h +++ b/lib/libutil/login_cap.h @@ -22,8 +22,7 @@ * Low-level routines relating to the user capabilities database * * Was login_cap.h,v 1.9 1997/05/07 20:00:01 eivind Exp - * $FreeBSD: src/lib/libutil/login_cap.h,v 1.3.2.1 2000/09/20 11:19:54 green Exp $ - * $DragonFly: src/lib/libutil/login_cap.h,v 1.5 2008/10/29 22:03:12 swildner Exp $ + * $FreeBSD: head/lib/libutil/login_cap.h 219304 2011-03-05 12:40:35Z trasz $ */ #ifndef _LOGIN_CAP_H_ @@ -48,7 +47,10 @@ #define LOGIN_SETUMASK 0x0020 /* set umask, obviously */ #define LOGIN_SETUSER 0x0040 /* set user (via setuid) */ #define LOGIN_SETENV 0x0080 /* set user environment */ -#define LOGIN_SETALL 0x00ff /* set everything */ +#define LOGIN_SETMAC 0x0100 /* set user default MAC label */ +#define LOGIN_SETCPUMASK 0x0200 /* set user cpumask */ +#define LOGIN_SETLOGINCLASS 0x0400 /* set login class in the kernel */ +#define LOGIN_SETALL 0x07ff /* set everything */ #define BI_AUTH "authorize" /* accepted authentication */ #define BI_REJECT "reject" /* rejected authentication */ @@ -97,63 +99,67 @@ typedef struct login_time { __BEGIN_DECLS struct passwd; -void login_close (login_cap_t *); -login_cap_t *login_getclassbyname (const char *, const struct passwd *); -login_cap_t *login_getclass (const char *); -login_cap_t *login_getpwclass (const struct passwd *); -login_cap_t *login_getuserclass (const struct passwd *); - -char *login_getcapstr (login_cap_t*, const char *, char *, char *); -char **login_getcaplist (login_cap_t *, const char *, const char *); -char *login_getstyle (login_cap_t *, char *, const char *); -rlim_t login_getcaptime (login_cap_t *, const char *, rlim_t, rlim_t); -rlim_t login_getcapnum (login_cap_t *, const char *, rlim_t, rlim_t); -rlim_t login_getcapsize (login_cap_t *, const char *, rlim_t, rlim_t); -char *login_getpath (login_cap_t *, const char *, char *); -int login_getcapbool (login_cap_t *, const char *, int); -const char *login_setcryptfmt (login_cap_t *, const char *, const char *); - -int setclasscontext (const char*, unsigned int); -int setusercontext (login_cap_t*, const struct passwd*, uid_t, unsigned int); -void setclassresources (login_cap_t *); -int setclassenvironment (login_cap_t *, const struct passwd *, int); +void login_close(login_cap_t *); +login_cap_t *login_getclassbyname(const char *, const struct passwd *); +login_cap_t *login_getclass(const char *); +login_cap_t *login_getpwclass(const struct passwd *); +login_cap_t *login_getuserclass(const struct passwd *); + +const char *login_getcapstr(login_cap_t *, const char *, const char *, + const char *); +const char **login_getcaplist(login_cap_t *, const char *, const char *); +const char *login_getstyle(login_cap_t *, const char *, const char *); +rlim_t login_getcaptime(login_cap_t *, const char *, rlim_t, rlim_t); +rlim_t login_getcapnum(login_cap_t *, const char *, rlim_t, rlim_t); +rlim_t login_getcapsize(login_cap_t *, const char *, rlim_t, rlim_t); +const char *login_getpath(login_cap_t *, const char *, const char *); +int login_getcapbool(login_cap_t *, const char *, int); +const char *login_setcryptfmt(login_cap_t *, const char *, const char *); + +int setclasscontext(const char *, unsigned int); +int setusercontext(login_cap_t *, const struct passwd *, uid_t, unsigned int); +void setclassresources(login_cap_t *); +void setclassenvironment(login_cap_t *, const struct passwd *, int); /* Most of these functions are deprecated */ -int auth_approve (login_cap_t*, const char*, const char*); -int auth_check (const char *, const char *, const char *, const char *, int *); -void auth_env (void); -char *auth_mkvalue (const char *n); -int auth_response (const char *, const char *, const char *, const char *, int *, const char *, const char *); -void auth_rmfiles (void); -int auth_scan (int); -int auth_script (const char*, ...); -int auth_script_data (const char *, int, const char *, ...); -char *auth_valud (const char *); -int auth_setopt (const char *, const char *); -void auth_clropts (void); - -void auth_checknologin (login_cap_t*); -int auth_cat (const char*); - -int auth_ttyok (login_cap_t*, const char *); -int auth_hostok (login_cap_t*, const char *, char const *); -int auth_timeok (login_cap_t*, time_t); +int auth_approve(login_cap_t *, const char *, const char *); +int auth_check(const char *, const char *, const char *, const char *, int *); +void auth_env(void); +char *auth_mkvalue(const char *); +int auth_response(const char *, const char *, const char *, const char *, int *, + const char *, const char *); +void auth_rmfiles(void); +int auth_scan(int); +int auth_script(const char *, ...); +int auth_script_data(const char *, int, const char *, ...); +char *auth_valud(const char *); +int auth_setopt(const char *, const char *); +void auth_clropts(void); + +void auth_checknologin(login_cap_t *); +int auth_cat(const char *); + +int auth_ttyok(login_cap_t *, const char *); +int auth_hostok(login_cap_t *, const char *, char const *); +int auth_timeok(login_cap_t *, time_t); struct tm; -login_time_t parse_lt (const char *); +login_time_t parse_lt(const char *); int in_lt(const login_time_t *, time_t *); -int in_ltm (const login_time_t *, struct tm *, time_t *); -int in_ltms (const login_time_t *, struct tm *, time_t *); +int in_ltm(const login_time_t *, struct tm *, time_t *); +int in_ltms(const login_time_t *, struct tm *, time_t *); int in_lts(const login_time_t *, time_t *); /* helper functions */ -int login_strinlist (char **, char const *, int); -int login_str2inlist (char **, const char *, const char *, int); -login_time_t * login_timelist (login_cap_t *, char const *, int *, login_time_t **); -int login_ttyok (login_cap_t *, const char *, const char *, const char *); -int login_hostok (login_cap_t *, const char *, const char *, const char *, const char *); +int login_strinlist(const char **, char const *, int); +int login_str2inlist(const char **, const char *, const char *, int); +login_time_t * login_timelist(login_cap_t *, char const *, int *, + login_time_t **); +int login_ttyok(login_cap_t *, const char *, const char *, const char *); +int login_hostok(login_cap_t *, const char *, const char *, const char *, + const char *); __END_DECLS diff --git a/lib/libutil/login_class.c b/lib/libutil/login_class.c index cf576a79f0..5df17ef809 100644 --- a/lib/libutil/login_class.c +++ b/lib/libutil/login_class.c @@ -21,28 +21,29 @@ * * High-level routines relating to use of the user capabilities database * - * $FreeBSD: src/lib/libutil/login_class.c,v 1.14.2.3 2002/08/06 07:07:52 ache Exp $ - * $DragonFly: src/lib/libutil/login_class.c,v 1.5 2006/01/12 13:43:10 corecode Exp $ + * $FreeBSD: head/lib/libutil/login_class.c 256850 2013-10-21 16:46:12Z kib $ */ #include -#include -#include #include #include +#include +#include +#include +#include #include #include +#include #include #include +#include #include #include #include #include #include -#include "login_cap.h" - static struct login_res { const char *what; @@ -105,7 +106,7 @@ setclassresources(login_cap_t *lc) rmax = (*lr->who)(lc, lr->what, rmax, rmax); rlim.rlim_cur = (*lr->who)(lc, name_cur, rcur, rcur); rlim.rlim_max = (*lr->who)(lc, name_max, rmax, rmax); - + if (setrlimit(lr->why, &rlim) == -1) syslog(LOG_WARNING, "set class '%s' resource limit %s: %m", lc->lc_class, lr->what); } @@ -133,7 +134,7 @@ static struct login_vars { }; static char * -substvar(char * var, const struct passwd * pwd, int hlen, int pch, int nlen) +substvar(const char * var, const struct passwd * pwd, int hlen, int pch, int nlen) { char *np = NULL; @@ -141,14 +142,13 @@ substvar(char * var, const struct passwd * pwd, int hlen, int pch, int nlen) int tildes = 0; int dollas = 0; char *p; + const char *q; if (pwd != NULL) { - /* Count the number of ~'s in var to substitute */ - for (p = var; (p = strchr(p, '~')) != NULL; p++) - ++tildes; - /* Count the number of $'s in var to substitute */ - for (p = var; (p = strchr(p, '$')) != NULL; p++) - ++dollas; + for (q = var; *q != '\0'; ++q) { + tildes += (*q == '~'); + dollas += (*q == '$'); + } } np = malloc(strlen(var) + (dollas * nlen) @@ -186,11 +186,11 @@ substvar(char * var, const struct passwd * pwd, int hlen, int pch, int nlen) } } - return np; + return (np); } -int +void setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths) { struct login_vars *vars = paths ? pathvars : envars; @@ -202,23 +202,16 @@ setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths) ++pch; while (vars->tag != NULL) { - char * var = paths ? login_getpath(lc, vars->tag, NULL) + const char * var = paths ? login_getpath(lc, vars->tag, NULL) : login_getcapstr(lc, vars->tag, NULL, NULL); char * np = substvar(var, pwd, hlen, pch, nlen); if (np != NULL) { - if (setenv(vars->var, np, vars->overwrite) == -1) { - syslog(LOG_ERR, "setclassenvironment: %m"); - free(np); - return -1; - } + setenv(vars->var, np, vars->overwrite); free(np); } else if (vars->def != NULL) { - if (setenv(vars->var, vars->def, 0) == -1) { - syslog(LOG_ERR, "setclassenvironment: %m"); - return -1; - } + setenv(vars->var, vars->def, 0); } ++vars; } @@ -228,7 +221,7 @@ setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths) * which the admin and/or user may set an arbitrary set of env vars. */ if (!paths) { - char **set_env = login_getcaplist(lc, "setenv", ","); + const char **set_env = login_getcaplist(lc, "setenv", ","); if (set_env != NULL) { while (*set_env != NULL) { @@ -239,10 +232,7 @@ setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths) *p++ = '\0'; if ((np = substvar(p, pwd, hlen, pch, nlen)) != NULL) { - if (setenv(*set_env, np, 1) == -1) { - free(np); - return -1; - } + setenv(*set_env, np, 1); free(np); } } @@ -250,10 +240,10 @@ setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths) } } } - return 0; } + /* * setclasscontext() * @@ -278,20 +268,19 @@ setclasscontext(const char *classname, unsigned int flags) rc = lc ? setusercontext(lc, NULL, 0, flags) : -1; login_close(lc); - return rc; + return (rc); } /* - * Private functionw which takes care of processing + * Private function which takes care of processing */ static mode_t setlogincontext(login_cap_t *lc, const struct passwd *pwd, - mode_t mymask, unsigned long flags, int *errcode) + mode_t mymask, unsigned long flags) { - *errcode = 0; if (lc) { /* Set resources */ if (flags & LOGIN_SETRESOURCES) @@ -300,17 +289,13 @@ setlogincontext(login_cap_t *lc, const struct passwd *pwd, if (flags & LOGIN_SETUMASK) mymask = (mode_t)login_getcapnum(lc, "umask", mymask, mymask); /* Set paths */ - if (flags & LOGIN_SETPATH) { - if (setclassenvironment(lc, pwd, 1) == -1) - *errcode = -1; - } + if (flags & LOGIN_SETPATH) + setclassenvironment(lc, pwd, 1); /* Set environment */ - if (flags & LOGIN_SETENV) { - if (setclassenvironment(lc, pwd, 0) == -1) - *errcode = -1; - } + if (flags & LOGIN_SETENV) + setclassenvironment(lc, pwd, 0); } - return mymask; + return (mymask); } @@ -335,10 +320,7 @@ setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned in quad_t p; mode_t mymask; login_cap_t *llc = NULL; -#ifndef __NETBSD_SYSCALLS struct rtprio rtp; -#endif - int errcode; if (lc == NULL) { if (pwd != NULL && (lc = login_getpwclass(pwd)) != NULL) @@ -356,25 +338,26 @@ setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned in if (flags & LOGIN_SETPRIORITY) { p = login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI); - if(p > PRIO_MAX) { -#ifndef __NETBSD_SYSCALLS + if (p > PRIO_MAX) { rtp.type = RTP_PRIO_IDLE; rtp.prio = p - PRIO_MAX - 1; - if(rtprio(RTP_SET, 0, &rtp)) - syslog(LOG_WARNING, "rtprio (%s): %m", + p = (rtp.prio > RTP_PRIO_MAX) ? 31 : p; + if (rtprio(RTP_SET, 0, &rtp)) + syslog(LOG_WARNING, "rtprio '%s' (%s): %m", + pwd ? pwd->pw_name : "-", lc ? lc->lc_class : LOGIN_DEFCLASS); -#endif - } else if(p < PRIO_MIN) { -#ifndef __NETBSD_SYSCALLS + } else if (p < PRIO_MIN) { rtp.type = RTP_PRIO_REALTIME; rtp.prio = abs(p - PRIO_MIN + RTP_PRIO_MAX); - if(rtprio(RTP_SET, 0, &rtp)) - syslog(LOG_WARNING, "rtprio (%s): %m", + p = (rtp.prio > RTP_PRIO_MAX) ? 1 : p; + if (rtprio(RTP_SET, 0, &rtp)) + syslog(LOG_WARNING, "rtprio '%s' (%s): %m", + pwd ? pwd->pw_name : "-", lc ? lc->lc_class : LOGIN_DEFCLASS); -#endif } else { if (setpriority(PRIO_PROCESS, 0, (int)p) != 0) - syslog(LOG_WARNING, "setpriority (%s): %m", + syslog(LOG_WARNING, "setpriority '%s' (%s): %m", + pwd ? pwd->pw_name : "-", lc ? lc->lc_class : LOGIN_DEFCLASS); } } @@ -384,13 +367,13 @@ setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned in if (setgid(pwd->pw_gid) != 0) { syslog(LOG_ERR, "setgid(%lu): %m", (u_long)pwd->pw_gid); login_close(llc); - return -1; + return (-1); } if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { syslog(LOG_ERR, "initgroups(%s,%lu): %m", pwd->pw_name, (u_long)pwd->pw_gid); login_close(llc); - return -1; + return (-1); } } @@ -398,32 +381,24 @@ setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned in if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) { syslog(LOG_ERR, "setlogin(%s): %m", pwd->pw_name); login_close(llc); - return -1; + return (-1); } mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0; - mymask = setlogincontext(lc, pwd, mymask, flags, &errcode); - if (errcode == -1) { - login_close(llc); - return -1; - } + mymask = setlogincontext(lc, pwd, mymask, flags); login_close(llc); /* This needs to be done after anything that needs root privs */ if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) { syslog(LOG_ERR, "setuid(%lu): %m", (u_long)uid); - return -1; /* Paranoia again */ + return (-1); /* Paranoia again */ } /* * Now, we repeat some of the above for the user's private entries */ - if ((lc = login_getuserclass(pwd)) != NULL) { - mymask = setlogincontext(lc, pwd, mymask, flags, &errcode); - if (errcode == -1) { - login_close(lc); - return -1; - } + if (getuid() == uid && (lc = login_getuserclass(pwd)) != NULL) { + mymask = setlogincontext(lc, pwd, mymask, flags); login_close(lc); } @@ -431,6 +406,5 @@ setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned in if (flags & LOGIN_SETUMASK) umask(mymask); - return 0; + return (0); } - diff --git a/lib/libutil/login_crypt.c b/lib/libutil/login_crypt.c index 2a4788337a..600e560f18 100644 --- a/lib/libutil/login_crypt.c +++ b/lib/libutil/login_crypt.c @@ -23,23 +23,21 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libutil/login_crypt.c,v 1.2.2.2 2000/10/27 01:50:31 green Exp $ - * $DragonFly: src/lib/libutil/login_crypt.c,v 1.3 2005/03/04 04:31:11 cpressey Exp $ + * $FreeBSD: head/lib/libutil/login_crypt.c 94202 2002-04-08 11:04:56Z ru $ */ #include +#include #include #include #include -#include "login_cap.h" - const char * login_setcryptfmt(login_cap_t *lc, const char *def, const char *error) { const char *cipher; - cipher = login_getcapstr(lc, "passwd_format", (char *)def, NULL); + cipher = login_getcapstr(lc, "passwd_format", def, NULL); if (getenv("CRYPT_DEBUG") != NULL) fprintf(stderr, "login_setcryptfmt: " "passwd_format = %s\n", cipher); diff --git a/lib/libutil/login_ok.3 b/lib/libutil/login_ok.3 index c9691ceee8..8e24c2fa21 100644 --- a/lib/libutil/login_ok.3 +++ b/lib/libutil/login_ok.3 @@ -17,7 +17,7 @@ .\" 5. Modifications may be freely made to this file providing the above .\" conditions are met. .\" -.\" $FreeBSD: src/lib/libutil/login_ok.3,v 1.7.2.4 2001/12/17 10:08:32 ru Exp $ +.\" $FreeBSD: head/lib/libutil/login_ok.3 206622 2010-04-14 19:08:06Z uqs $ .\" .Dd January 2, 1997 .Dt LOGIN_OK 3 @@ -44,8 +44,9 @@ This set of functions checks to see if login is allowed based on login class capability entries in the login database, .Xr login.conf 5 . .Pp +The .Fn auth_ttyok -checks to see if the named tty is available to users of a specific +function checks to see if the named tty is available to users of a specific class, and is either in the .Em ttys.allow access list, and not in @@ -55,7 +56,7 @@ access list. An empty .Em ttys.allow list (or if no such capability exists for -the give login class) logins via any tty device are allowed unless +the given login class) logins via any tty device are allowed unless the .Em ttys.deny list exists and is non-empty, and the device or its @@ -63,7 +64,7 @@ tty group (see .Xr ttys 5 ) is not in the list. Access to ttys may be allowed or restricted specifically by tty device -name, a device name which includes a wildcard (e.g. ttyD* or cuaD*), +name, a device name which includes a wildcard (e.g.\& ttyD* or cuaD*), or may name a ttygroup, when group= tags have been assigned in .Pa /etc/ttys . Matching of ttys and ttygroups is case sensitive. @@ -73,8 +74,9 @@ or empty string as the .Ar tty parameter causes the function to return a non-zero value. .Pp +The .Fn auth_hostok -checks for any host restrictions for remote logins. +function checks for any host restrictions for remote logins. The function checks on both a host name and IP address (given in its text form, typically n.n.n.n) against the .Em host.allow @@ -88,7 +90,7 @@ The function is used for matching, and the matching on hostnames is case insensitive. Note that this function expects that the hostname is fully expanded -(i.e. the local domain name added if necessary) and the IP address +(i.e., the local domain name added if necessary) and the IP address is in its canonical form. No hostname or address lookups are attempted. .Pp diff --git a/lib/libutil/login_ok.c b/lib/libutil/login_ok.c index 6f41be888a..b0637ef848 100644 --- a/lib/libutil/login_ok.c +++ b/lib/libutil/login_ok.c @@ -20,23 +20,21 @@ * * Support allow/deny lists in login class capabilities * - * $FreeBSD: src/lib/libutil/login_ok.c,v 1.7.2.1 2001/01/10 21:01:30 ghelmer Exp $ - * $DragonFly: src/lib/libutil/login_ok.c,v 1.3 2005/03/04 04:31:11 cpressey Exp $ + * $FreeBSD: head/lib/libutil/login_ok.c 154414 2006-01-16 00:28:11Z rwatson $ */ #include #include #include #include - #include #include +#include #include #include #include #include -#include "login_cap.h" /* -- support functions -- */ @@ -49,7 +47,7 @@ */ int -login_strinlist(char **list, char const *str, int flags) +login_strinlist(const char **list, char const *str, int flags) { int rc = 0; @@ -69,7 +67,7 @@ login_strinlist(char **list, char const *str, int flags) */ int -login_str2inlist(char **ttlst, const char *str1, const char *str2, int flags) +login_str2inlist(const char **ttlst, const char *str1, const char *str2, int flags) { int rc = 0; @@ -83,7 +81,7 @@ login_str2inlist(char **ttlst, const char *str1, const char *str2, int flags) /* * login_timelist() - * This function is intentinoally public - reused by TAS. + * This function is intentionally public - reused by TAS. * Returns an allocated list of time periods given an array * of time periods in ascii form. */ @@ -94,7 +92,7 @@ login_timelist(login_cap_t *lc, char const *cap, int *ltno, { int j = 0; struct login_time *lt = NULL; - char **tl; + const char **tl; if ((tl = login_getcaplist(lc, cap, NULL)) != NULL) { @@ -134,7 +132,7 @@ login_ttyok(login_cap_t *lc, const char *tty, const char *allowcap, if (lc != NULL && tty != NULL && *tty != '\0') { struct ttyent *te; char *grp; - char **ttl; + const char **ttl; te = getttynam(tty); /* Need group name */ grp = te ? te->ty_group : NULL; @@ -182,7 +180,7 @@ login_hostok(login_cap_t *lc, const char *host, const char *ip, if (lc != NULL && ((host != NULL && *host != '\0') || (ip != NULL && *ip != '\0'))) { - char **hl; + const char **hl; hl = login_getcaplist(lc, allowcap, NULL); if (hl != NULL && !login_str2inlist(hl, host, ip, FNM_CASEFOLD)) diff --git a/lib/libutil/login_times.3 b/lib/libutil/login_times.3 index 5b78f91c4c..2c4a5a5d18 100644 --- a/lib/libutil/login_times.3 +++ b/lib/libutil/login_times.3 @@ -17,9 +17,9 @@ .\" 5. Modifications may be freely made to this file providing the above .\" conditions are met. .\" -.\" $FreeBSD: src/lib/libutil/login_times.3,v 1.16 2008/10/20 17:17:58 des Exp $ +.\" $FreeBSD: head/lib/libutil/login_times.3 206622 2010-04-14 19:08:06Z uqs $ .\" -.Dd October 29, 2008 +.Dd October 20, 2008 .Dt LOGIN_TIMES 3 .Os .Sh NAME diff --git a/lib/libutil/login_times.c b/lib/libutil/login_times.c index e90fce20b0..f0e8ae7cc1 100644 --- a/lib/libutil/login_times.c +++ b/lib/libutil/login_times.c @@ -20,19 +20,16 @@ * * Login period parsing and comparison functions. * - * $FreeBSD: src/lib/libutil/login_times.c,v 1.7 1999/08/28 00:05:48 peter Exp $ - * $DragonFly: src/lib/libutil/login_times.c,v 1.3 2005/03/04 04:31:11 cpressey Exp $ + * $FreeBSD: head/lib/libutil/login_times.c 252376 2013-06-29 15:52:48Z kientzle $ */ #include - #include +#include #include #include #include -#include "login_cap.h" - static struct { const char *dw; @@ -56,12 +53,12 @@ parse_time(char * ptr, u_short * t) *t = (u_short)((val / 100) * 60 + (val % 100)); - return ptr; + return (ptr); } login_time_t -parse_lt(const char * str) +parse_lt(const char *str) { login_time_t t; @@ -74,10 +71,10 @@ parse_lt(const char * str) char buf[64]; /* Make local copy and force lowercase to simplify parsing */ - p = strncpy(buf, str, sizeof buf); - buf[sizeof buf - 1] = '\0'; + strlcpy(buf, str, sizeof buf); for (i = 0; buf[i]; i++) buf[i] = (char)tolower(buf[i]); + p = buf; while (isalpha(*p)) { @@ -98,18 +95,18 @@ parse_lt(const char * str) else m.lt_start = 0; if (*p == '-') - p = parse_time(++p, &m.lt_end); + p = parse_time(p + 1, &m.lt_end); else m.lt_end = 1440; t = m; } - return t; + return (t); } int -in_ltm(const login_time_t * ltm, struct tm * tt, time_t * ends) +in_ltm(const login_time_t *ltm, struct tm *tt, time_t *ends) { int rc = 0; @@ -132,32 +129,33 @@ in_ltm(const login_time_t * ltm, struct tm * tt, time_t * ends) } } } - return rc; + return (rc); } int -in_lt(const login_time_t * ltm, time_t * t) +in_lt(const login_time_t *ltm, time_t *t) { - return in_ltm(ltm, localtime(t), t); + + return (in_ltm(ltm, localtime(t), t)); } int -in_ltms(const login_time_t * ltm, struct tm * tm, time_t * t) +in_ltms(const login_time_t *ltm, struct tm *tm, time_t *t) { int i = 0; while (i < LC_MAXTIMES && ltm[i].lt_dow != LTM_NONE) { if (in_ltm(ltm + i, tm, t)) - return i; + return (i); i++; } - return -1; + return (-1); } int -in_lts(const login_time_t * ltm, time_t * t) +in_lts(const login_time_t *ltm, time_t *t) { - return in_ltms(ltm, localtime(t), t); -} + return (in_ltms(ltm, localtime(t), t)); +} diff --git a/lib/libutil/login_tty.3 b/lib/libutil/login_tty.3 index 7f400861fc..4d5767b240 100644 --- a/lib/libutil/login_tty.3 +++ b/lib/libutil/login_tty.3 @@ -23,8 +23,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libutil/login_tty.3,v 1.5.2.3 2001/12/17 10:08:32 ru Exp $ -.\" +.\" $FreeBSD: head/lib/libutil/login_tty.3 206622 2010-04-14 19:08:06Z uqs $ +.\" " .Dd December 29, 1996 .Dt LOGIN_TTY 3 .Os @@ -41,19 +41,22 @@ .Sh DESCRIPTION The function .Fn login_tty -prepares a terminal for a new login session. The file descriptor +prepares a terminal for a new login session. +The file descriptor .Ar fd passed to .Fn login_tty -must be opened for reading and writing on a terminal device. It will be +must be opened for reading and writing on a terminal device. +It will be made the controlling terminal for the calling process, after allocating a new session with .Xr setsid 2 . This terminal device will also be made the standard input, standard output, and standard error output of the calling process. .Sh RETURN VALUES -.Fn Login_tty -returns -1 if it could not make the device referenced by +The +.Fn login_tty +function returns -1 if it could not make the device referenced by .Ar fd the controlling terminal of the calling process, and 0 otherwise. .Sh SEE ALSO diff --git a/lib/libutil/login_tty.c b/lib/libutil/login_tty.c index 6f973f209f..90f37c5f9f 100644 --- a/lib/libutil/login_tty.c +++ b/lib/libutil/login_tty.c @@ -28,17 +28,15 @@ * * @(#)login_tty.c 8.1 (Berkeley) 6/4/93 * $FreeBSD: src/lib/libutil/login_tty.c,v 1.6 1999/08/28 00:05:49 peter Exp $ - * $DragonFly: src/lib/libutil/login_tty.c,v 1.5 2007/12/30 13:44:33 matthias Exp $ */ #include #include +#include #include #include -#include "libutil.h" - int login_tty(int fd) { diff --git a/lib/libutil/logout.c b/lib/libutil/logout.c index 3fe23883c4..9667cbc3a4 100644 --- a/lib/libutil/logout.c +++ b/lib/libutil/logout.c @@ -28,7 +28,6 @@ * * @(#)logout.c 8.1 (Berkeley) 6/4/93 * $FreeBSD: src/lib/libutil/logout.c,v 1.6.2.2 2000/09/20 09:54:16 jkh Exp $ - * $DragonFly: src/lib/libutil/logout.c,v 1.5 2007/12/30 13:44:33 matthias Exp $ */ #include @@ -39,8 +38,7 @@ #include #include #include - -#include "libutil.h" +#include typedef struct utmp UTMP; diff --git a/lib/libutil/logwtmp.c b/lib/libutil/logwtmp.c index 79ea1e16f6..a26237ffce 100644 --- a/lib/libutil/logwtmp.c +++ b/lib/libutil/logwtmp.c @@ -41,8 +41,7 @@ #include #include #include - -#include "libutil.h" +#include /* wrapper for KAME-special getnameinfo() */ #ifndef NI_WITHSCOPEID diff --git a/lib/libutil/pidfile.3 b/lib/libutil/pidfile.3 index 48e7116e8e..8d70ebd02e 100644 --- a/lib/libutil/pidfile.3 +++ b/lib/libutil/pidfile.3 @@ -1,12 +1,6 @@ -.\" $NetBSD: pidfile.3,v 1.8 2002/10/01 19:36:30 wiz Exp $ -.\" $DragonFly: src/lib/libutil/pidfile.3,v 1.2 2005/05/22 17:48:57 liamfoy Exp $ -.\" -.\" Copyright (c) 1999 The NetBSD Foundation, Inc. +.\" Copyright (c) 2005 Pawel Jakub Dawidek .\" 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: @@ -15,83 +9,289 @@ .\" 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 the NetBSD -.\" Foundation, Inc. and its contributors. -.\" 4. Neither the name of The NetBSD Foundation 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 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. +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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. +.\" +.\" $FreeBSD: head/lib/libutil/pidfile.3 231193 2012-02-08 08:49:30Z pjd $ .\" -.Dd June 5, 1999 +.Dd February 8, 2012 .Dt PIDFILE 3 .Os .Sh NAME -.Nm pidfile -.Nd write a daemon pid file +.Nm pidfile_open , +.Nm pidfile_write , +.Nm pidfile_close , +.Nm pidfile_remove +.Nd "library for PID files handling" .Sh LIBRARY .Lb libutil .Sh SYNOPSIS -.In sys/types.h .In libutil.h +.Ft "struct pidfh *" +.Fn pidfile_open "const char *path" "mode_t mode" "pid_t *pidptr" +.Ft int +.Fn pidfile_write "struct pidfh *pfh" .Ft int -.Fn pidfile "const char *basename" +.Fn pidfile_close "struct pidfh *pfh" +.Ft int +.Fn pidfile_remove "struct pidfh *pfh" +.Ft int +.Fn pidfile_fileno "struct pidfh *pfh" .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 . +The +.Nm pidfile +family of functions allows daemons to handle PID files. +It uses +.Xr flopen 3 +to lock a pidfile and detect already running daemons. +.Pp +The +.Fn pidfile_open +function opens (or creates) a file specified by the +.Fa path +argument and locks it. +If +.Fa pidptr +argument is not +.Dv NULL +and file can not be locked, the function will use it to store a PID of an +already running daemon or +.Li -1 +in case daemon did not write its PID yet. +The function does not write process' PID into the file here, so it can be +used before +.Fn fork Ns ing +and exit with a proper error message when needed. If the -.Ar basename -argument is NULL, -.Nm -will determine the program name and use that instead. +.Fa path +argument is +.Dv NULL , +.Pa /var/run/ Ns Ao Va progname Ac Ns Pa .pid +file will be used. +The +.Fn pidfile_open +function sets the O_CLOEXEC close-on-exec flag when opening the pidfile. +.Pp +The +.Fn pidfile_write +function writes process' PID into a previously opened file. +The file is truncated before write, so calling the +.Fn pidfile_write +function multiple times is supported. +.Pp +The +.Fn pidfile_close +function closes a pidfile. +It should be used after daemon +.Fn fork Ns s +to start a child process. .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. +The +.Fn pidfile_remove +function closes and removes a pidfile. .Pp -Note that only the first invocation of -.Nm -causes a pid file to be written; subsequent invocations have no effect -unless a new -.Ar basename -is supplied. -If called with a new -.Ar basename , -.Fn pidfile -will remove the old pid file and write the new one. +The +.Fn pidfile_fileno +function returns the file descriptor for the open pidfile. .Sh RETURN VALUES -.Fn pidfile -returns 0 on success and -1 on failure. +The +.Fn pidfile_open +function returns a valid pointer to a +.Vt pidfh +structure on success, or +.Dv NULL +if an error occurs. +If an error occurs, +.Va errno +will be set. +.Pp +.Rv -std pidfile_write pidfile_close pidfile_remove +.Pp +The +.Fn pidfile_fileno +function returns the low-level file descriptor. +It returns +.Li -1 +and sets +.Va errno +if a NULL +.Vt pidfh +is specified, or if the pidfile is no longer open. +.Sh EXAMPLES +The following example shows in which order these functions should be used. +Note that it is safe to pass +.Dv NULL +to +.Fn pidfile_write , +.Fn pidfile_remove , +.Fn pidfile_close +and +.Fn pidfile_fileno +functions. +.Bd -literal +struct pidfh *pfh; +pid_t otherpid, childpid; + +pfh = pidfile_open("/var/run/daemon.pid", 0600, &otherpid); +if (pfh == NULL) { + if (errno == EEXIST) { + errx(EXIT_FAILURE, "Daemon already running, pid: %jd.", + (intmax_t)otherpid); + } + /* If we cannot create pidfile from other reasons, only warn. */ + warn("Cannot open or create pidfile"); + /* + * Eventhough pfh is NULL we can continue, as the other pidfile_* + * function can handle such situation by doing nothing except setting + * errno to EDOOFUS. + */ +} + +if (daemon(0, 0) == -1) { + warn("Cannot daemonize"); + pidfile_remove(pfh); + exit(EXIT_FAILURE); +} + +pidfile_write(pfh); + +for (;;) { + /* Do work. */ + childpid = fork(); + switch (childpid) { + case -1: + syslog(LOG_ERR, "Cannot fork(): %s.", strerror(errno)); + break; + case 0: + pidfile_close(pfh); + /* Do child work. */ + break; + default: + syslog(LOG_INFO, "Child %jd started.", (intmax_t)childpid); + break; + } +} + +pidfile_remove(pfh); +exit(EXIT_SUCCESS); +.Ed +.Sh ERRORS +The +.Fn pidfile_open +function will fail if: +.Bl -tag -width Er +.It Bq Er EEXIST +Some process already holds the lock on the given pidfile, meaning that a +daemon is already running. +If +.Fa pidptr +argument is not +.Dv NULL +the function will use it to store a PID of an already running daemon or +.Li -1 +in case daemon did not write its PID yet. +.It Bq Er ENAMETOOLONG +Specified pidfile's name is too long. +.It Bq Er EINVAL +Some process already holds the lock on the given pidfile, but PID read +from there is invalid. +.El +.Pp +The +.Fn pidfile_open +function may also fail and set +.Va errno +for any errors specified for the +.Xr fstat 2 , +.Xr open 2 , +and +.Xr read 2 +calls. +.Pp +The +.Fn pidfile_write +function will fail if: +.Bl -tag -width Er +.It Bq Er EDOOFUS +Improper function use. +Probably called before +.Fn pidfile_open . +.El +.Pp +The +.Fn pidfile_write +function may also fail and set +.Va errno +for any errors specified for the +.Xr fstat 2 , +.Xr ftruncate 2 , +and +.Xr write 2 +calls. +.Pp +The +.Fn pidfile_close +function may fail and set +.Va errno +for any errors specified for the +.Xr close 2 +and +.Xr fstat 2 +calls. +.Pp +The +.Fn pidfile_remove +function will fail if: +.Bl -tag -width Er +.It Bq Er EDOOFUS +Improper function use. +Probably called not from the process which made +.Fn pidfile_write . +.El +.Pp +The +.Fn pidfile_remove +function may also fail and set +.Va errno +for any errors specified for the +.Xr close 2 , +.Xr fstat 2 , +.Xr write 2 , +and +.Xr unlink 2 +system calls and the +.Xr flopen 3 +library function. +.Pp +The +.Fn pidfile_fileno +function will fail if: +.Bl -tag -width Er +.It Bq Er EDOOFUS +Improper function use. +Probably called not from the process which used +.Fn pidfile_open . +.El .Sh SEE ALSO -.Xr atexit 3 -.Sh HISTORY -The -.Nm -function call appeared in -.Nx 1.5 . -.Sh BUGS -.Fn pidfile -uses -.Xr atexit 3 -to ensure the pidfile is unlinked at program exit. -However, programs that use the -.Xr _exit 2 -function (for example, in signal handlers) -will not trigger this behaviour. +.Xr open 2 , +.Xr daemon 3 , +.Xr flopen 3 +.Sh AUTHORS +.An -nosplit +The +.Nm pidfile +functionality is based on ideas from +.An John-Mark Gurney Aq Mt jmg@FreeBSD.org . +.Pp +The code and manual page was written by +.An Pawel Jakub Dawidek Aq Mt pjd@FreeBSD.org . diff --git a/lib/libutil/pidfile.c b/lib/libutil/pidfile.c index 4d7a5076a8..29e8597771 100644 --- a/lib/libutil/pidfile.c +++ b/lib/libutil/pidfile.c @@ -1,13 +1,7 @@ -/* $NetBSD: pidfile.c,v 1.6 2001/10/20 09:20:28 taca Exp $ */ -/* $DragonFly: src/lib/libutil/pidfile.c,v 1.2 2005/03/04 04:31:11 cpressey Exp $ */ - /*- - * Copyright (c) 1999 The NetBSD Foundation, Inc. + * Copyright (c) 2005 Pawel Jakub Dawidek * All rights reserved. * - * This code is derived from software contributed to The NetBSD Foundation - * by Jason R. Thorpe and Matthias Scheler. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,110 +10,267 @@ * 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 the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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. + * + * $FreeBSD: head/lib/libutil/pidfile.c 255007 2013-08-28 21:10:37Z jilles $ */ #include +#include -#include #include #include -#include #include +#include +#include +#include +#include +#include +#include -#include "libutil.h" +struct pidfh { + int pf_fd; + char pf_path[MAXPATHLEN + 1]; + dev_t pf_dev; + ino_t pf_ino; +}; -static int pidfile_atexit_done; -static pid_t pidfile_pid; -static char *pidfile_basename; -static char *pidfile_path; +static int _pidfile_remove(struct pidfh *pfh, int freeit); -static void pidfile_cleanup(void); +static int +pidfile_verify(const struct pidfh *pfh) +{ + struct stat sb; -int -pidfile(const char *basename) + if (pfh == NULL || pfh->pf_fd == -1) + return (EDOOFUS); + /* + * Check remembered descriptor. + */ + if (fstat(pfh->pf_fd, &sb) == -1) + return (errno); + if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino) + return (EDOOFUS); + return (0); +} + +static int +pidfile_read(const char *path, pid_t *pidptr) { - FILE *f; + char buf[16], *endptr; + int error, fd, i; + + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd == -1) + return (errno); + + i = read(fd, buf, sizeof(buf) - 1); + error = errno; /* Remember errno in case close() wants to change it. */ + close(fd); + if (i == -1) + return (error); + else if (i == 0) + return (EAGAIN); + buf[i] = '\0'; + + *pidptr = strtol(buf, &endptr, 10); + if (endptr != &buf[i]) + return (EINVAL); + + return (0); +} + +struct pidfh * +pidfile_open(const char *path, mode_t mode, pid_t *pidptr) +{ + struct pidfh *pfh; + struct stat sb; + int error, fd, len, count; + struct timespec rqtp; + + pfh = malloc(sizeof(*pfh)); + if (pfh == NULL) + return (NULL); + + if (path == NULL) + len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), + "/var/run/%s.pid", getprogname()); + else + len = snprintf(pfh->pf_path, sizeof(pfh->pf_path), + "%s", path); + if (len >= (int)sizeof(pfh->pf_path)) { + free(pfh); + errno = ENAMETOOLONG; + return (NULL); + } /* - * Register handler which will remove the pidfile later. + * Open the PID file and obtain exclusive lock. + * We truncate PID file here only to remove old PID immediatelly, + * PID file will be truncated again in pidfile_write(), so + * pidfile_write() can be called multiple times. */ - if (!pidfile_atexit_done) { - if (atexit(pidfile_cleanup) < 0) - return -1; - pidfile_atexit_done = 1; + fd = flopen(pfh->pf_path, + O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode); + if (fd == -1) { + if (errno == EWOULDBLOCK) { + if (pidptr == NULL) { + errno = EEXIST; + } else { + count = 20; + rqtp.tv_sec = 0; + rqtp.tv_nsec = 5000000; + for (;;) { + errno = pidfile_read(pfh->pf_path, + pidptr); + if (errno != EAGAIN || --count == 0) + break; + nanosleep(&rqtp, 0); + } + if (errno == EAGAIN) + *pidptr = -1; + if (errno == 0 || errno == EAGAIN) + errno = EEXIST; + } + } + free(pfh); + return (NULL); } - if (basename == NULL) - basename = getprogname(); + /* + * Remember file information, so in pidfile_write() we are sure we write + * to the proper descriptor. + */ + if (fstat(fd, &sb) == -1) { + error = errno; + unlink(pfh->pf_path); + close(fd); + free(pfh); + errno = error; + return (NULL); + } + + pfh->pf_fd = fd; + pfh->pf_dev = sb.st_dev; + pfh->pf_ino = sb.st_ino; + + return (pfh); +} + +int +pidfile_write(struct pidfh *pfh) +{ + char pidstr[16]; + int error, fd; /* - * If pidfile has already been created for the supplied basename - * we don't need to create a pidfile again. + * Check remembered descriptor, so we don't overwrite some other + * file if pidfile was closed and descriptor reused. */ - if (pidfile_path != NULL) { - if (strcmp(pidfile_basename, basename) == 0) - return 0; + errno = pidfile_verify(pfh); + if (errno != 0) { /* - * Remove existing pidfile if it was created by this process. + * Don't close descriptor, because we are not sure if it's ours. */ - pidfile_cleanup(); + return (-1); + } + fd = pfh->pf_fd; + + /* + * Truncate PID file, so multiple calls of pidfile_write() are allowed. + */ + if (ftruncate(fd, 0) == -1) { + error = errno; + _pidfile_remove(pfh, 0); + errno = error; + return (-1); + } + + snprintf(pidstr, sizeof(pidstr), "%u", getpid()); + if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) { + error = errno; + _pidfile_remove(pfh, 0); + errno = error; + return (-1); + } + + return (0); +} + +int +pidfile_close(struct pidfh *pfh) +{ + int error; - free(pidfile_path); - pidfile_path = NULL; - free(pidfile_basename); - pidfile_basename = NULL; + error = pidfile_verify(pfh); + if (error != 0) { + errno = error; + return (-1); } - pidfile_pid = getpid(); + if (close(pfh->pf_fd) == -1) + error = errno; + free(pfh); + if (error != 0) { + errno = error; + return (-1); + } + return (0); +} - pidfile_basename = strdup(basename); - if (pidfile_basename == NULL) - return -1; +static int +_pidfile_remove(struct pidfh *pfh, int freeit) +{ + int error; - /* _PATH_VARRUN includes trailing / */ - asprintf(&pidfile_path, "%s%s.pid", _PATH_VARRUN, basename); - if (pidfile_path == NULL) { - free(pidfile_basename); - pidfile_basename = NULL; - return -1; + error = pidfile_verify(pfh); + if (error != 0) { + errno = error; + return (-1); } - if ((f = fopen(pidfile_path, "w")) == NULL) { - free(pidfile_path); - pidfile_path = NULL; - free(pidfile_basename); - pidfile_basename = NULL; - return -1; + if (unlink(pfh->pf_path) == -1) + error = errno; + if (close(pfh->pf_fd) == -1) { + if (error == 0) + error = errno; + } + if (freeit) + free(pfh); + else + pfh->pf_fd = -1; + if (error != 0) { + errno = error; + return (-1); } + return (0); +} - fprintf(f, "%d\n", pidfile_pid); - fclose(f); - return 0; +int +pidfile_remove(struct pidfh *pfh) +{ + + return (_pidfile_remove(pfh, 1)); } -static void -pidfile_cleanup(void) +int +pidfile_fileno(const struct pidfh *pfh) { - /* Only remove the pidfile if it was created by this process. */ - if ((pidfile_path != NULL) && (pidfile_pid == getpid())) - unlink(pidfile_path); + + if (pfh == NULL || pfh->pf_fd == -1) { + errno = EDOOFUS; + return (-1); + } + return (pfh->pf_fd); } diff --git a/lib/libutil/property.3 b/lib/libutil/property.3 index 397ac1dc9b..23b5190732 100644 --- a/lib/libutil/property.3 +++ b/lib/libutil/property.3 @@ -23,8 +23,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libutil/property.3,v 1.8.2.7 2001/12/17 10:08:32 ru Exp $ -.\" +.\" $FreeBSD: head/lib/libutil/property.3 236965 2012-06-12 17:02:53Z des $ +.\" " .Dd October 7, 1998 .Dt PROPERTIES 3 .Os @@ -36,7 +36,6 @@ .Sh LIBRARY .Lb libutil .Sh SYNOPSIS -.In sys/types.h .In libutil.h .Ft properties .Fn properties_read "int fd" @@ -63,15 +62,18 @@ and returns the head of a new property list, assuming that the file's contents have been parsed properly, or NULL in case of error. .Pp +The .Fn property_find -Returns the associated value string for the property named +function returns the associated value string for the property named .Fa name -if found, otherwise NULL. The value returned may be up to +if found, otherwise NULL. +The value returned may be up to .Dv PROPERTY_MAX_VALUE bytes in length. .Pp +The .Fn properties_free -is used to free the structure returned by +function is used to free the structure returned by .Fn properties_read when it is no longer needed. .Sh FILE FORMAT @@ -82,12 +84,12 @@ where is an alphanumeric string (and any punctuation not including the `=' character) and .Fa value -is an arbitrary string of text terminated by a newline character. If newlines +is an arbitrary string of text terminated by a newline character. +If newlines are desired, the entire value should be enclosed in { } (curly-bracket) -characters. Any line beginning with a # or ; character is assumed to +characters. +Any line beginning with a # or ; character is assumed to be a comment and will be ignored. -.Sh SEE ALSO -.Xr auth_getval 3 .Sh AUTHORS .An Jordan Hubbard .Sh BUGS diff --git a/lib/libutil/property.c b/lib/libutil/property.c index 1b8ae96153..28f64904b0 100644 --- a/lib/libutil/property.c +++ b/lib/libutil/property.c @@ -28,32 +28,42 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libutil/property.c,v 1.5.6.1 2000/11/22 03:49:49 murray Exp $ - * $DragonFly: src/lib/libutil/property.c,v 1.3 2005/03/04 04:31:11 cpressey Exp $ - * + * $FreeBSD: head/lib/libutil/property.c 152886 2005-11-28 16:30:16Z jhb $ */ #include - #include #include -#include +#include #include +#include #include #include -#include "libutil.h" - static properties property_alloc(char *name, char *value) { properties n; - n = (properties)malloc(sizeof(struct _property)); + if ((n = (properties)malloc(sizeof(struct _property))) == NULL) + return (NULL); n->next = NULL; - n->name = name ? strdup(name) : NULL; - n->value = value ? strdup(value) : NULL; - return n; + if (name != NULL) { + if ((n->name = strdup(name)) == NULL) { + free(n); + return (NULL); + } + } else + n->name = NULL; + if (value != NULL) { + if ((n->value = strdup(value)) == NULL) { + free(n->name); + free(n); + return (NULL); + } + } else + n->value = NULL; + return (n); } properties @@ -64,41 +74,51 @@ properties_read(int fd) char hold_v[PROPERTY_MAX_VALUE + 1]; char buf[BUFSIZ * 4]; int bp, n, v, max; - enum { LOOK, COMMENT, NAME, VALUE, MVALUE, COMMIT, FILL, STOP } state; + enum { LOOK, COMMENT, NAME, VALUE, MVALUE, COMMIT, FILL, STOP } state, last_state; int ch = 0, blevel = 0; n = v = bp = max = 0; head = ptr = NULL; - state = LOOK; + state = last_state = LOOK; while (state != STOP) { if (state != COMMIT) { - if (bp == max) + if (bp == max) { + last_state = state; state = FILL; - else + } else ch = buf[bp++]; } switch(state) { case FILL: - if ((max = read(fd, buf, sizeof buf)) <= 0) { - state = STOP; - break; + if ((max = read(fd, buf, sizeof buf)) < 0) { + properties_free(head); + return (NULL); } - else { - state = LOOK; + if (max == 0) { + state = STOP; + } else { + /* + * Restore the state from before the fill (which will be + * initialised to LOOK for the first FILL). This ensures that + * if we were part-way through eg., a VALUE state, when the + * buffer ran out, that the previous operation will be allowed + * to complete. + */ + state = last_state; ch = buf[0]; - bp = 1; + bp = 0; } - /* Fall through deliberately since we already have a character and state == LOOK */ + continue; case LOOK: - if (isspace(ch)) + if (isspace((unsigned char)ch)) continue; /* Allow shell or lisp style comments */ else if (ch == '#' || ch == ';') { state = COMMENT; continue; } - else if (isalnum(ch) || ch == '_') { + else if (isalnum((unsigned char)ch) || ch == '_') { if (n >= PROPERTY_MAX_NAME) { n = 0; state = COMMENT; @@ -124,7 +144,7 @@ properties_read(int fd) v = n = 0; state = COMMIT; } - else if (isspace(ch)) + else if (isspace((unsigned char)ch)) continue; else if (ch == '=') { hold_n[n] = '\0'; @@ -141,7 +161,7 @@ properties_read(int fd) v = n = 0; state = COMMIT; } - else if (v == 0 && isspace(ch)) + else if (v == 0 && isspace((unsigned char)ch)) continue; else if (ch == '{') { state = MVALUE; @@ -183,10 +203,14 @@ properties_read(int fd) break; case COMMIT: - if (!head) - head = ptr = property_alloc(hold_n, hold_v); - else { - ptr->next = property_alloc(hold_n, hold_v); + if (head == NULL) { + if ((head = ptr = property_alloc(hold_n, hold_v)) == NULL) + return (NULL); + } else { + if ((ptr->next = property_alloc(hold_n, hold_v)) == NULL) { + properties_free(head); + return (NULL); + } ptr = ptr->next; } state = LOOK; @@ -198,20 +222,23 @@ properties_read(int fd) break; } } - return head; + if (head == NULL && (head = property_alloc(NULL, NULL)) == NULL) + return (NULL); + + return (head); } char * property_find(properties list, const char *name) { - if (!list || !name || !name[0]) - return NULL; - while (list) { - if (!strcmp(list->name, name)) - return list->value; + if (list == NULL || name == NULL || !name[0]) + return (NULL); + while (list != NULL) { + if (list->name != NULL && strcmp(list->name, name) == 0) + return (list->value); list = list->next; } - return NULL; + return (NULL); } void diff --git a/lib/libutil/pty.3 b/lib/libutil/pty.3 index 165975ceef..f5a66c896a 100644 --- a/lib/libutil/pty.3 +++ b/lib/libutil/pty.3 @@ -23,8 +23,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libutil/pty.3,v 1.8.2.3 2001/12/17 10:08:32 ru Exp $ -.\" +.\" $FreeBSD: head/lib/libutil/pty.3 206622 2010-04-14 19:08:06Z uqs $ +.\" " .Dd December 29, 1996 .Dt PTY 3 .Os @@ -48,13 +48,13 @@ The function .Fn openpty attempts to obtain the next available pseudo-terminal from the system (see .Xr pty 4 ) . -If it successfully finds one, it subsequently tries to change the +If it successfully finds one, it subsequently changes the ownership of the slave device to the real UID of the current process, the group membership to the group .Dq tty (if such a group exists in the system), the access permissions for -reading and writing by the owner, and for writing by the group, and to -invalidate any current use of the line by calling +reading and writing by the owner, and for writing by the group, and +invalidates any current use of the line by calling .Xr revoke 2 . .Pp If the argument @@ -62,7 +62,8 @@ If the argument is not .Dv NULL , .Fn openpty -copies the pathname of the slave pty to this area. The caller is +copies the pathname of the slave pty to this area. +The caller is responsible for allocating the required space in this array. .Pp If the arguments @@ -82,15 +83,20 @@ and .Fa aslave , respectively. .Pp -.Fn Forkpty -first calls +The +.Fn forkpty +function first calls .Fn openpty -to obtain the next available pseudo-terminal from the system. Upon success, -it forks off a new process. In the child process, it closes the descriptor +to obtain the next available pseudo-terminal from the system. +Upon success, +it forks off a new process. +In the child process, it closes the descriptor for the master side of the pty, and calls .Xr login_tty 3 -for the slave pty. In the parent process, it closes the descriptor for the -slave side of the pty. The arguments +for the slave pty. +In the parent process, it closes the descriptor for the +slave side of the pty. +The arguments .Fa amaster , .Fa name , .Fa termp , @@ -99,19 +105,28 @@ and have the same meaning as described for .Fn openpty . .Sh RETURN VALUES -.Fn Openpty -returns 0 on success, or -1 on failure. +The +.Fn openpty +function returns 0 on success, or -1 on failure. .Pp -.Fn Forkpty -returns -1 on failure, 0 in the slave process, and the process ID of the -slave process in the parent process. +The +.Fn forkpty +function returns -1 on failure, 0 in the slave process, and the process ID of +the slave process in the parent process. .Sh ERRORS -On failure, +The .Fn openpty -will set the global variable -.Va errno -to -.Er ENOENT . +function may fail and set the global variable +.Dv errno +for any of the errors specified for the +.Xr grantpt 3 , +.Xr posix_openpt 3 , +.Xr ptsname 3 , +and +.Xr unlockpt 3 +functions and the +.Xr revoke 2 +system call. .Pp In addition to this, .Fn forkpty @@ -128,13 +143,3 @@ may set it to any value as described for .Xr pty 4 , .Xr termios 4 , .Xr group 5 -.Sh BUGS -The calling process must have an effective UID of super-user in order -to perform all the intended actions. No notification will occur if -.Fn openpty -or -.Fn forkpty -failed to proceed with one of the described steps, as long as they could -at least allocate the pty at all (and create the new process in the case -of -.Fn forkpty ) . diff --git a/lib/libutil/pty.c b/lib/libutil/pty.c index d90f77544d..885dd5d702 100644 --- a/lib/libutil/pty.c +++ b/lib/libutil/pty.c @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * @(#)pty.c 8.3 (Berkeley) 5/16/94 - * $FreeBSD: src/lib/libutil/pty.c,v 1.10 1999/08/28 00:05:51 peter Exp $ + * $FreeBSD: head/lib/libutil/pty.c 184634 2008-11-04 13:50:50Z des $ */ #include @@ -37,59 +37,42 @@ #include #include #include +#include #include #include #include #include -#include "libutil.h" - int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp) { - char line[] = "/dev/ptyXX"; - const char *cp1, *cp2; - int master, slave, ttygid; - struct group *gr; - const char *slave_name; - - if ((gr = getgrnam("tty")) != NULL) - ttygid = gr->gr_gid; - else - ttygid = -1; + const char *slavename; + int master, slave; master = posix_openpt(O_RDWR|O_NOCTTY); if (master == -1) - goto fallback; + return (-1); - if (grantpt(master) != 0) { - close(master); - goto fallback; - } + if (grantpt(master) == -1) + goto bad; - if (unlockpt(master) != 0) { - close(master); - goto fallback; - } + if (unlockpt(master) == -1) + goto bad; - slave_name = ptsname(master); - if (slave_name == NULL) { - close(master); - goto fallback; - } + slavename = ptsname(master); + if (slavename == NULL) + goto bad; - slave = open(slave_name, O_RDWR); - if (slave == -1) { - close(master); - goto fallback; - } + slave = open(slavename, O_RDWR); + if (slave == -1) + goto bad; *amaster = master; *aslave = slave; if (name) - strcpy(name, slave_name); + strcpy(name, slavename); if (termp) tcsetattr(slave, TCSAFLUSH, termp); if (winp) @@ -97,38 +80,7 @@ openpty(int *amaster, int *aslave, char *name, struct termios *termp, return (0); -fallback: - for (cp1 = "pqrsPQRS"; *cp1; cp1++) { - line[8] = *cp1; - for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) { - line[5] = 'p'; - line[9] = *cp2; - if ((master = open(line, O_RDWR, 0)) == -1) { - if (errno == ENOENT) - return (-1); /* out of ptys */ - } else { - line[5] = 't'; - (void) chown(line, getuid(), ttygid); - (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); - (void) revoke(line); - if ((slave = open(line, O_RDWR, 0)) != -1) { - *amaster = master; - *aslave = slave; - if (name) - strcpy(name, line); - if (termp) - (void) tcsetattr(slave, - TCSAFLUSH, termp); - if (winp) - (void) ioctl(slave, TIOCSWINSZ, - (char *)winp); - return (0); - } - (void) close(master); - } - } - } - errno = ENOENT; /* out of ptys */ +bad: close(master); return (-1); } diff --git a/lib/libutil/pw_util.3 b/lib/libutil/pw_util.3 new file mode 100644 index 0000000000..1655c9bc78 --- /dev/null +++ b/lib/libutil/pw_util.3 @@ -0,0 +1,286 @@ +.\" Copyright (c) 2012 Baptiste Daroussin +.\" 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 AUTHORS 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 AUTHORS 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. +.\" +.\" $FreeBSD: head/lib/libutil/pw_util.3 242503 2012-11-03 00:30:22Z bapt $ +.\" +.Dd October 30, 2012 +.Dt PW_UTIL 3 +.Os +.Sh NAME +.Nm pw_copy , +.Nm pw_dup , +.Nm pw_edit , +.Nm pw_equal , +.Nm pw_fini , +.Nm pw_init , +.Nm pw_make , +.Nm pw_make_v7 , +.Nm pw_mkdb , +.Nm pw_lock , +.Nm pw_scan , +.Nm pw_tempname , +.Nm pw_tmp +.Nd "functions for passwd file handling" +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In pwd.h +.In libutil.h +.Ft int +.Fn pw_copy "int ffd" "int tfd" "const struct passwd *pw" "const struct passwd *oldpw" +.Ft "struct passwd *" +.Fn pw_dup "const struct passwd *pw" +.Ft int +.Fn pw_edit "int nosetuid" +.Ft int +.Fn pw_equal "const struct passwd *pw1" "const struct passwd pw2" +.Ft void +.Fn pw_fini "void" +.Ft int +.Fn pw_init "const char *dir" const char *master" +.Ft "char *" +.Fn pw_make "const struct passwd *pw" +.Ft "char *" +.Fn pw_make_v7 "const struct passwd *pw" +.Ft int +.Fn pw_mkdb "const char *user" +.Ft int +.Fn pw_lock "void" +.Ft "struct passwd *" +.Fn pw_scan "const char *line" "int flags" +.Ft "const char *" +.Fn pw_tempname "void" +.Ft int +.Fn pw_tmp "int mfd" +.Sh DESCRIPTION +The +.Fn pw_copy +function reads a password file from +.Vt ffd +and writes it back out to +.Vt tfd +possibly with modifications: +.Bl -dash +.It +If +.Fa pw +is +.Dv NULL +and +.Fa oldpw +is not +.Dv NULL , +then the record represented by +.Fa oldpw +will not be copied (corresponding to user deletion). +.It +If +.Fa pw +and +.Fa oldpw +are not +.Dv NULL +then the record corresponding to +.Fa pw +will be replaced by the record corresponding to +.Fa oldpw . +.It +If +.Vt pw +is set and +.Vt oldpw +is +.Dv NULL +then the record corresponding to +.Vt pw +will be appended (corresponding to user addition). +.El +.Pp +The +.Fn pw_copy +function returns -1 in case of failure otherwise 0. +.Pp +The +.Fn pw_dup +function duplicates the +.Vt struct passwd +pointed to by +.Fa pw +and returns a pointer to the copy, or +.Dv NULL +in case of failure. +The new +.Vt struct passwd +is allocated with +.Xr malloc 3 , +and it is the caller's responsibility to free it with +.Xr free 3 . +.Pp +The +.Fn pw_edit +function invokes the command specified by the +.Ev EDITOR +environment variable (or +.Pa /usr/bin/vi +if +.Ev EDITOR +is not defined) +on a temporary copy of the master password file created by +.Fn pw_tmp . +If the file was modified, +.Fn pw_edit +installs it and regenerates the password database. +The +.Fn pw_edit +function returns -1 in case of failure, 0 if the file was not modified, +and a non-zero positive number if the file was modified and successfully +installed. +.Pp +The +.Fn pw_equal +function compares two +.Vt struct passwd +and returns 0 if they are equal. +.Pp +The +.Fn pw_fini +function destroy the temporary file created by +.Fn pw_tmp +if any, +kills any running instance of +.Ev EDITOR +executed by +.Fn pw_edit +if any, +and closes the lock created by +.Fn pw_lock +if any. +.Pp +The +.Fn pw_init +initialize the static variable representing the path a password file. +.Fa dir +is the directory where the password file is located. +If set to +.Dv NULL , +it will default to +.Pa /etc . +.Fa master +is the name of the password file. +If set to +.Dv NULL? +it will default to +.Pa master.passwd +.Pp +The +.Fn pw_make +function creates a properly formatted +.Bx +.Xr passwd 5 +line from a +.Vt struct passwd , +and returns a pointer to the resulting string. +The string is allocated with +.Xr malloc 3 , +and it is the caller's responsibility to free it with +.Xr free 3 . +.Pp +The +.Fn pw_make_v7 +function creates a properly formatted +.Ux V7 +.Xr passwd 5 +line from a +.Vt struct passwd , +and returns a pointer to the resulting string. +The string is allocated with +.Xr malloc 3 , +and it is the caller's responsibility to free it with +.Xr free 3 . +.Pp +The +.Fn pw_mkdb +function regenerates the password database by running +.Xr pw_mkdb 8 . +If +.Fa user +only the record corresponding to that user will be updated. +The +.Fn pw_mkdb +function returns 0 in case of success and -1 in case of failure. +.Pp +The +.Fn pw_lock +function locks the master password file. +It returns 0 in case of success and -1 in case of failure. +.Pp +The +.Fn pw_scan +function is a wrapper around the internal libc function +.Fn __pw_scan . +It scans the master password file for a line corresponding to the +.Fa line +provided and return a +.Vt struct passwd +if it matched an existing record. +In case of failure, it returns +.Dv NULL . +Otherwise, it returns a pointer to a +.Vt struct passwd +containing the matching record. +The +.Vt struct passwd +is allocated with +.Xr malloc 3 , +and it is the caller's responsibility to free it with +.Xr free 3 . +.Pp +The +.Fn pw_tempname +function returns the temporary name of the masterfile created via +.Fn pw_tmp . +.Pp +The +.Fn pw_tmp +creates and opens a presumably safe temporary password file. +If +.Fa mfd +is a file descriptor to an open password file, it will be read and +written back to the temporary password file. +Otherwise if should be set -1. +The +.Fn pw_tmp +returns an open file descriptor to the temporary password file or -1 in case of +failure. +.Sh AUTHORS +Portions of this software were developed for the +.Fx +Project by ThinkSec AS and Network Associates Laboratories, the +Security Research Division of Network Associates, Inc.\& under +DARPA/SPAWAR contract N66001-01-C-8035 +.Pq Dq CBOSS , +as part of the DARPA CHATS research program. +.Pp +This manual page was written by +.An Baptiste Daroussin Aq bapt@FreeBSD.org . diff --git a/lib/libutil/pw_util.c b/lib/libutil/pw_util.c index 5c4a7f6a08..1d4df24d4c 100644 --- a/lib/libutil/pw_util.c +++ b/lib/libutil/pw_util.c @@ -34,8 +34,7 @@ * SUCH DAMAGE. * * @(#)pw_util.c 8.3 (Berkeley) 4/2/94 - * $FreeBSD: src/lib/libutil/pw_util.c,v 1.38 2007/01/09 01:02:05 imp Exp $ - * $DragonFly: src/lib/libutil/pw_util.c,v 1.2 2007/12/30 13:44:33 matthias Exp $ + * $FreeBSD: head/lib/libutil/pw_util.c 244744 2012-12-27 20:24:44Z bapt $ */ /* @@ -62,7 +61,6 @@ #include #include #include - #include static pid_t editpid = -1; @@ -175,11 +173,8 @@ pw_lock(void) for (;;) { struct stat st; - lockfd = open(masterpasswd, O_RDONLY, 0); - if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) - err(1, "%s", masterpasswd); - /* XXX vulnerable to race conditions */ - if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) { + lockfd = flopen(masterpasswd, O_RDONLY|O_NONBLOCK|O_CLOEXEC, 0); + if (lockfd == -1) { if (errno == EWOULDBLOCK) { errx(1, "the password db file is busy"); } else { @@ -258,11 +253,11 @@ pw_mkdb(const char *user) /* child */ if (user == NULL) execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", - "-d", passwd_dir, tempname, NULL); + "-d", passwd_dir, tempname, (char *)NULL); else execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", passwd_dir, "-u", user, tempname, - NULL); + (char *)NULL); _exit(1); /* NOTREACHED */ default: @@ -285,7 +280,7 @@ int pw_edit(int notsetuid) { struct sigaction sa, sa_int, sa_quit; - sigset_t oldsigset, sigset; + sigset_t oldsigset, nsigset; struct stat st1, st2; const char *editor; int pstat; @@ -299,9 +294,9 @@ pw_edit(int notsetuid) sa.sa_flags = 0; sigaction(SIGINT, &sa, &sa_int); sigaction(SIGQUIT, &sa, &sa_quit); - sigemptyset(&sigset); - sigaddset(&sigset, SIGCHLD); - sigprocmask(SIG_BLOCK, &sigset, &oldsigset); + sigemptyset(&nsigset); + sigaddset(&nsigset, SIGCHLD); + sigprocmask(SIG_BLOCK, &nsigset, &oldsigset); switch ((editpid = fork())) { case -1: return (-1); @@ -310,11 +305,11 @@ pw_edit(int notsetuid) sigaction(SIGQUIT, &sa_quit, NULL); sigprocmask(SIG_SETMASK, &oldsigset, NULL); if (notsetuid) { - setgid(getgid()); - setuid(getuid()); + (void)setgid(getgid()); + (void)setuid(getuid()); } errno = 0; - execlp(editor, basename(editor), tempname, NULL); + execlp(editor, basename(editor), tempname, (char *)NULL); _exit(errno); default: /* parent */ @@ -343,7 +338,8 @@ pw_edit(int notsetuid) sigprocmask(SIG_SETMASK, &oldsigset, NULL); if (stat(tempname, &st2) == -1) return (-1); - return (st1.st_mtime != st2.st_mtime); + return (st1.st_mtim.tv_sec != st2.st_mtim.tv_sec || + st1.st_mtim.tv_nsec != st2.st_mtim.tv_nsec); } /* @@ -402,26 +398,55 @@ pw_make(const struct passwd *pw) pw->pw_passwd, (uintmax_t)pw->pw_uid, (uintmax_t)pw->pw_gid, pw->pw_class, (uintmax_t)pw->pw_change, (uintmax_t)pw->pw_expire, pw->pw_gecos, pw->pw_dir, pw->pw_shell); - return line; + return (line); } /* - * Copy password file from one descriptor to another, replacing or adding - * a single record on the way. + * Make a passwd line (in v7 format) out of a struct passwd + */ +char * +pw_make_v7(const struct passwd *pw) +{ + char *line; + + asprintf(&line, "%s:*:%ju:%ju:%s:%s:%s", pw->pw_name, + (uintmax_t)pw->pw_uid, (uintmax_t)pw->pw_gid, + pw->pw_gecos, pw->pw_dir, pw->pw_shell); + return (line); +} + +/* + * Copy password file from one descriptor to another, replacing, deleting + * or adding a single record on the way. */ int pw_copy(int ffd, int tfd, const struct passwd *pw, struct passwd *old_pw) { char buf[8192], *end, *line, *p, *q, *r, t; struct passwd *fpw; + const struct passwd *spw; size_t len; int eof, readlen; + if (old_pw == NULL && pw == NULL) + return (-1); + + spw = old_pw; + /* deleting a user */ + if (pw == NULL) { + line = NULL; + } else { if ((line = pw_make(pw)) == NULL) return (-1); + } + + /* adding a user */ + if (spw == NULL) + spw = pw; eof = 0; - q = end = buf; + len = 0; + p = q = end = buf; for (;;) { /* find the end of the current line */ for (p = q; q < end && *q != '\0'; ++q) @@ -455,7 +480,7 @@ pw_copy(int ffd, int tfd, const struct passwd *pw, struct passwd *old_pw) if (len < (ssize_t)sizeof(buf)) { eof = 1; if (len > 0 && buf[len - 1] != '\n') - *end++ = '\n'; + ++len, *end++ = '\n'; } continue; } @@ -484,7 +509,7 @@ pw_copy(int ffd, int tfd, const struct passwd *pw, struct passwd *old_pw) */ *q = t; - if (fpw == NULL || strcmp(fpw->pw_name, pw->pw_name) != 0) { + if (fpw == NULL || strcmp(fpw->pw_name, spw->pw_name) != 0) { /* nope */ if (fpw != NULL) free(fpw); @@ -501,11 +526,15 @@ pw_copy(int ffd, int tfd, const struct passwd *pw, struct passwd *old_pw) } free(fpw); - /* it is, replace it */ + /* it is, replace or remove it */ + if (line != NULL) { len = strlen(line); if (write(tfd, line, len) != (int)len) goto err; - + } else { + /* when removed, avoid the \n */ + q++; + } /* we're done, just copy the rest over */ for (;;) { if (write(tfd, q, end - q) != end - q) @@ -523,15 +552,21 @@ pw_copy(int ffd, int tfd, const struct passwd *pw, struct passwd *old_pw) goto done; } - /* if we got here, we have a new entry */ + /* if we got here, we didn't find the old entry */ + if (line == NULL) { + errno = ENOENT; + goto err; + } len = strlen(line); if ((size_t)write(tfd, line, len) != len || write(tfd, "\n", 1) != 1) goto err; done: + if (line != NULL) free(line); return (0); err: + if (line != NULL) free(line); return (-1); } @@ -552,43 +587,50 @@ pw_tempname(void) struct passwd * pw_dup(const struct passwd *pw) { + char *dst; struct passwd *npw; ssize_t len; - len = sizeof(*npw) + - (pw->pw_name ? strlen(pw->pw_name) + 1 : 0) + - (pw->pw_passwd ? strlen(pw->pw_passwd) + 1 : 0) + - (pw->pw_class ? strlen(pw->pw_class) + 1 : 0) + - (pw->pw_gecos ? strlen(pw->pw_gecos) + 1 : 0) + - (pw->pw_dir ? strlen(pw->pw_dir) + 1 : 0) + - (pw->pw_shell ? strlen(pw->pw_shell) + 1 : 0); + len = sizeof(*npw); + if (pw->pw_name != NULL) + len += strlen(pw->pw_name) + 1; + if (pw->pw_passwd != NULL) + len += strlen(pw->pw_passwd) + 1; + if (pw->pw_class != NULL) + len += strlen(pw->pw_class) + 1; + if (pw->pw_gecos != NULL) + len += strlen(pw->pw_gecos) + 1; + if (pw->pw_dir != NULL) + len += strlen(pw->pw_dir) + 1; + if (pw->pw_shell != NULL) + len += strlen(pw->pw_shell) + 1; if ((npw = malloc((size_t)len)) == NULL) return (NULL); memcpy(npw, pw, sizeof(*npw)); - len = sizeof(*npw); - if (pw->pw_name) { - npw->pw_name = ((char *)npw) + len; - len += sprintf(npw->pw_name, "%s", pw->pw_name) + 1; + dst = (char *)npw + sizeof(*npw); + if (pw->pw_name != NULL) { + npw->pw_name = dst; + dst = stpcpy(npw->pw_name, pw->pw_name) + 1; } - if (pw->pw_passwd) { - npw->pw_passwd = ((char *)npw) + len; - len += sprintf(npw->pw_passwd, "%s", pw->pw_passwd) + 1; + if (pw->pw_passwd != NULL) { + npw->pw_passwd = dst; + dst = stpcpy(npw->pw_passwd, pw->pw_passwd) + 1; } - if (pw->pw_class) { - npw->pw_class = ((char *)npw) + len; - len += sprintf(npw->pw_class, "%s", pw->pw_class) + 1; + if (pw->pw_class != NULL) { + npw->pw_class = dst; + dst = stpcpy(npw->pw_class, pw->pw_class) + 1; } - if (pw->pw_gecos) { - npw->pw_gecos = ((char *)npw) + len; - len += sprintf(npw->pw_gecos, "%s", pw->pw_gecos) + 1; + if (pw->pw_gecos != NULL) { + npw->pw_gecos = dst; + dst = stpcpy(npw->pw_gecos, pw->pw_gecos) + 1; } - if (pw->pw_dir) { - npw->pw_dir = ((char *)npw) + len; - len += sprintf(npw->pw_dir, "%s", pw->pw_dir) + 1; + if (pw->pw_dir != NULL) { + npw->pw_dir = dst; + dst = stpcpy(npw->pw_dir, pw->pw_dir) + 1; } - if (pw->pw_shell) { - npw->pw_shell = ((char *)npw) + len; - len += sprintf(npw->pw_shell, "%s", pw->pw_shell) + 1; + if (pw->pw_shell != NULL) { + npw->pw_shell = dst; + dst = stpcpy(npw->pw_shell, pw->pw_shell) + 1; } return (npw); } diff --git a/lib/libutil/realhostname.3 b/lib/libutil/realhostname.3 index 6cfeb68517..e8e92d037f 100644 --- a/lib/libutil/realhostname.3 +++ b/lib/libutil/realhostname.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libutil/realhostname.3,v 1.4.2.2 2001/12/17 10:08:32 ru Exp $ +.\" $FreeBSD: head/lib/libutil/realhostname.3 230234 2012-01-16 21:25:41Z ghelmer $ .\" .Dd April 6, 1999 .Dt REALHOSTNAME 3 @@ -33,8 +33,6 @@ .Sh LIBRARY .Lb libutil .Sh SYNOPSIS -.In sys/types.h -.In netinet/in.h .In libutil.h .Ft int .Fn realhostname "char *host" "size_t hsize" "const struct in_addr *ip" @@ -43,7 +41,8 @@ The function .Fn realhostname converts .Ar ip -to the corresponding host name. This is done by resolving +to the corresponding host name. +This is done by resolving .Ar ip to a host name and then ensuring that the host name resolves back to @@ -54,7 +53,7 @@ must point to a buffer of at least .Ar hsize bytes, and will always be written to by this function. .Pp -If the name resolution doesn't work both ways or if the host name is longer +If the name resolution does not work both ways or if the host name is longer than .Ar hsize bytes, @@ -71,8 +70,9 @@ bytes long, .Ar host will not be NUL terminated. .Sh RETURN VALUES +The .Fn realhostname -will return one of the following constants which are defined in +function will return one of the following constants which are defined in .In libutil.h : .Bl -tag -width XXX -offset XXX .It Li HOSTNAME_FOUND diff --git a/lib/libutil/realhostname.c b/lib/libutil/realhostname.c index c86ffb5689..04b8a50c56 100644 --- a/lib/libutil/realhostname.c +++ b/lib/libutil/realhostname.c @@ -23,26 +23,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libutil/realhostname.c,v 1.6.2.6 2002/06/29 18:26:37 ume Exp $ - * $DragonFly: src/lib/libutil/realhostname.c,v 1.2 2003/06/17 04:26:52 dillon Exp $ + * $FreeBSD: head/lib/libutil/realhostname.c 185277 2008-11-25 02:15:09Z avatar $ */ #include - #include + #include #include #include #include #include - -#include "libutil.h" - -/* wrapper for KAME-special getnameinfo() */ -#ifndef NI_WITHSCOPEID -#define NI_WITHSCOPEID 0 -#endif +#include struct sockinet { u_char si_len; @@ -58,7 +51,7 @@ realhostname(char *host, size_t hsize, const struct in_addr *ip) struct hostent *hp; result = HOSTNAME_INVALIDADDR; - hp = gethostbyaddr(ip, sizeof(*ip), AF_INET); + hp = gethostbyaddr((const char *)ip, sizeof(*ip), AF_INET); if (hp != NULL) { strlcpy(trimmed, hp->h_name, sizeof(trimmed)); @@ -66,8 +59,7 @@ realhostname(char *host, size_t hsize, const struct in_addr *ip) if (strlen(trimmed) <= hsize) { char lookup[MAXHOSTNAMELEN]; - strncpy(lookup, hp->h_name, sizeof(lookup) - 1); - lookup[sizeof(lookup) - 1] = '\0'; + strlcpy(lookup, hp->h_name, sizeof(lookup)); hp = gethostbyname(lookup); if (hp == NULL) result = HOSTNAME_INVALIDNAME; @@ -89,12 +81,26 @@ realhostname(char *host, size_t hsize, const struct in_addr *ip) return result; } +/* + * struct sockaddr has very lax alignment requirements, since all its + * members are char or equivalent. This is a problem when trying to + * dereference a struct sockaddr_in6 * that was passed in as a struct + * sockaddr *. Although we know (or trust) that the passed-in struct was + * properly aligned, the compiler doesn't, and (rightly) complains. These + * macros perform the cast in a way that the compiler will accept. + */ +#define SOCKADDR_IN6(p) ((struct sockaddr_in6 *)(void *)(p)) +#define SOCKADDR_IN(p) ((struct sockaddr_in *)(void *)(p)) +#define SOCKINET(p) ((struct sockinet *)(void *)(p)) + int realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, int addrlen) { int result, error; char buf[NI_MAXHOST]; - struct sockaddr_in sin; +#ifdef INET6 + struct sockaddr_in lsin; +#endif result = HOSTNAME_INVALIDADDR; @@ -102,24 +108,24 @@ realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, int addrlen) /* IPv4 mapped IPv6 addr consideraton, specified in rfc2373. */ if (addr->sa_family == AF_INET6 && addrlen == sizeof(struct sockaddr_in6) && - IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)addr)->sin6_addr)) { + IN6_IS_ADDR_V4MAPPED(&SOCKADDR_IN6(addr)->sin6_addr)) { struct sockaddr_in6 *sin6; - sin6 = (struct sockaddr_in6 *)addr; + sin6 = SOCKADDR_IN6(addr); - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_family = AF_INET; - sin.sin_port = sin6->sin6_port; - memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12], + memset(&lsin, 0, sizeof(lsin)); + lsin.sin_len = sizeof(struct sockaddr_in); + lsin.sin_family = AF_INET; + lsin.sin_port = sin6->sin6_port; + memcpy(&lsin.sin_addr, &sin6->sin6_addr.s6_addr[12], sizeof(struct in_addr)); - addr = (struct sockaddr *)&sin; - addrlen = sin.sin_len; + addr = (struct sockaddr *)&lsin; + addrlen = lsin.sin_len; } #endif error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, - NI_WITHSCOPEID | NI_NAMEREQD); + NI_NAMEREQD); if (error == 0) { struct addrinfo hints, *res, *ores; struct sockaddr *sa; @@ -148,15 +154,16 @@ realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, int addrlen) } if (sa->sa_len == addrlen && sa->sa_family == addr->sa_family) { - ((struct sockinet *)sa)->si_port = ((struct sockinet *)addr)->si_port; + SOCKINET(sa)->si_port = SOCKINET(addr)->si_port; #ifdef INET6 /* * XXX: sin6_socpe_id may not been * filled by DNS */ if (sa->sa_family == AF_INET6 && - ((struct sockaddr_in6 *)sa)->sin6_scope_id == 0) - ((struct sockaddr_in6 *)sa)->sin6_scope_id = ((struct sockaddr_in6 *)addr)->sin6_scope_id; + SOCKADDR_IN6(sa)->sin6_scope_id == 0) + SOCKADDR_IN6(sa)->sin6_scope_id = + SOCKADDR_IN6(addr)->sin6_scope_id; #endif if (!memcmp(sa, addr, sa->sa_len)) { result = HOSTNAME_FOUND; @@ -181,7 +188,7 @@ realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, int addrlen) } else { numeric: if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, - NI_NUMERICHOST|NI_WITHSCOPEID) == 0) + NI_NUMERICHOST) == 0) strncpy(host, buf, hsize); } diff --git a/lib/libutil/realhostname_sa.3 b/lib/libutil/realhostname_sa.3 index 3726163dbc..c359ea498d 100644 --- a/lib/libutil/realhostname_sa.3 +++ b/lib/libutil/realhostname_sa.3 @@ -49,14 +49,16 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libutil/realhostname_sa.3,v 1.2.2.3 2001/12/17 10:08:32 ru Exp $ +.\" $FreeBSD: head/lib/libutil/realhostname_sa.3 213573 2010-10-08 12:40:16Z uqs $ .\" .Dd January 11, 2000 .Dt REALHOSTNAME_SA 3 .Os .Sh NAME .Nm realhostname_sa -.Nd "convert an struct sockaddr to the real host name" +.Nd "convert a" +.Vt "struct sockaddr" +to the real host name .Sh LIBRARY .Lb libutil .Sh SYNOPSIS @@ -70,7 +72,8 @@ The function .Fn realhostname_sa converts .Ar addr -to the corresponding host name. This is done by resolving +to the corresponding host name. +This is done by resolving .Ar addr to a host name and then ensuring that the host name resolves back to @@ -81,7 +84,7 @@ must point to a buffer of at least .Ar hsize bytes, and will always be written to by this function. .Pp -If the name resolution doesn't work both ways or if the host name is longer +If the name resolution does not work both ways or if the host name is longer than .Ar hsize bytes, @@ -98,8 +101,9 @@ bytes long, .Ar host will not be NUL terminated. .Sh RETURN VALUES +The .Fn realhostname_sa -will return one of the following constants which are defined in +function will return one of the following constants which are defined in .In libutil.h : .Bl -tag -width XXX -offset XXX .It Li HOSTNAME_FOUND diff --git a/lib/libutil/stub.c b/lib/libutil/stub.c index b3271d92b2..77406ab9e2 100644 --- a/lib/libutil/stub.c +++ b/lib/libutil/stub.c @@ -23,8 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libutil/stub.c,v 1.1.2.1 2000/10/27 01:50:31 green Exp $ - * $DragonFly: src/lib/libutil/stub.c,v 1.3 2008/10/29 22:03:12 swildner Exp $ + * $FreeBSD: head/lib/libutil/stub.c 121193 2003-10-18 10:04:16Z markm $ */ #include @@ -36,6 +35,7 @@ */ #pragma weak crypt_set_format +/* ARGSUSED */ int crypt_set_format(const char *f __unused) { diff --git a/lib/libutil/trimdomain.3 b/lib/libutil/trimdomain.3 index b6628c12c1..ecbca21b0c 100644 --- a/lib/libutil/trimdomain.3 +++ b/lib/libutil/trimdomain.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libutil/trimdomain.3,v 1.3.2.3 2001/12/17 10:08:32 ru Exp $ +.\" $FreeBSD: head/lib/libutil/trimdomain.3 206622 2010-04-14 19:08:06Z uqs $ .\" .Dd April 7, 1999 .Dt TRIMDOMAIN 3 @@ -44,14 +44,17 @@ removes the current domain name from the passed .Ar fullhost name by writing a .Dv NUL -character over the first period of the passed name. The current domain +character over the first period of the passed name. +The current domain name is determined by calling .Xr gethostname 3 -and removing everything up to the first period. The name is determined +and removing everything up to the first period. +The name is determined the first time this function is called and is cached for future use. .Pp +The .Fn trimdomain -will only trim the domain name if the passed +function will only trim the domain name if the passed .Ar fullname ends with the current domain name and if the length of the resulting host name does not exceed @@ -75,7 +78,8 @@ numbers to the end of the base host name and resulting in .Ar host : nn Op . Ar nn . .Sm on .Sh RETURN VALUES +The .Fn trimdomain -does not return a value. +function does not return a value. .Sh SEE ALSO .Xr gethostname 3 diff --git a/lib/libutil/trimdomain.c b/lib/libutil/trimdomain.c index db08ea3518..937fd768f2 100644 --- a/lib/libutil/trimdomain.c +++ b/lib/libutil/trimdomain.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 2001 Brian Somers * Based on original work by Atsushi Murai * All rights reserved. @@ -24,16 +24,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: /repoman/r/ncvs/src/lib/libutil/trimdomain.c,v 1.5 2003/10/18 10:04:16 markm Exp $ + * $FreeBSD: head/lib/libutil/trimdomain.c 150955 2005-10-05 04:42:20Z brooks $ */ #include +#include #include #include -#include "libutil.h" - static int isDISP(const char *); /*- @@ -74,18 +73,16 @@ trimdomain(char *fullhost, int hostsize) s = fullhost; end = s + hostsize + 1; - for (; (s = memchr(s, '.', (size_t)(end - s))) != NULL; s++) { + if ((s = memchr(s, '.', (size_t)(end - s))) != NULL) { if (strncasecmp(s + 1, domain, dlen) == 0) { if (s[dlen + 1] == '\0') { /* Found -- lose the domain. */ *s = '\0'; - break; } else if (s[dlen + 1] == ':' && isDISP(s + dlen + 2) && (len = strlen(s + dlen + 1)) < (size_t)(end - s)) { /* Found -- shuffle the DISPLAY back. */ memmove(s, s + dlen + 1, len + 1); - break; } } } diff --git a/lib/libutil/uucplock.3 b/lib/libutil/uucplock.3 index 743bd5adb2..324befadf4 100644 --- a/lib/libutil/uucplock.3 +++ b/lib/libutil/uucplock.3 @@ -23,8 +23,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libutil/uucplock.3,v 1.13.2.4 2001/12/17 10:08:32 ru Exp $ -.\" +.\" $FreeBSD: head/lib/libutil/uucplock.3 206622 2010-04-14 19:08:06Z uqs $ +.\" " .Dd March 30, 1997 .Dt UUCPLOCK 3 .Os @@ -103,7 +103,7 @@ The lock file could not be read via .Xr read 2 . .Pp .Dv UU_LOCK_CREAT_ERR : -Can't create temporary lock file via +Cannot create temporary lock file via .Xr creat 2 . .Pp .Dv UU_LOCK_WRITE_ERR : @@ -111,7 +111,7 @@ 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 +Cannot link temporary lock file via .Xr link 2 . .Pp .Dv UU_LOCK_TRY_ERR : @@ -127,7 +127,8 @@ 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 +to determine the exact error. +Care should be made not to allow .Va errno to be changed between calls to .Fn uu_lock @@ -138,7 +139,8 @@ and may return any of the following values: .Pp .Dv UU_LOCK_OK : -The transfer was successful. The specified process now holds the device +The transfer was successful. +The specified process now holds the device lock. .Pp .Dv UU_LOCK_OWNER_ERR : @@ -152,7 +154,8 @@ 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 +can be used to determine the cause. +Refer to the respective manual pages for further details. .Pp .Fn uu_unlock @@ -174,6 +177,7 @@ 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 +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 index 47d158c326..9a96e9baf5 100644 --- a/lib/libutil/uucplock.c +++ b/lib/libutil/uucplock.c @@ -26,26 +26,23 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libutil/uucplock.c,v 1.12.2.1 2000/10/09 20:20:52 brian Exp $ - * $DragonFly: src/lib/libutil/uucplock.c,v 1.6 2007/12/30 13:44:33 matthias Exp $ + * $FreeBSD: head/lib/libutil/uucplock.c 255007 2013-08-28 21:10:37Z jilles $ * * @(#)uucplock.c 8.1 (Berkeley) 6/6/93 */ #include #include - #include -#include #include +#include #include #include #include #include #include #include - -#include "libutil.h" +#include #define MAXTRIES 5 @@ -68,8 +65,8 @@ uu_lock(const char *tty_name) { int fd, tmpfd, i; pid_t pid, pid_old; - char lckname[PATH_MAX], - lcktmpname[PATH_MAX]; + char lckname[sizeof(_PATH_UUCPLOCK) + NAME_MAX], + lcktmpname[sizeof(_PATH_UUCPLOCK) + NAME_MAX]; int err, uuerr; pid = getpid(); @@ -77,7 +74,8 @@ uu_lock(const char *tty_name) pid); (void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, tty_name); - if ((tmpfd = creat(lcktmpname, 0664)) < 0) + if ((tmpfd = open(lcktmpname, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, + 0664)) < 0) GORET(0, UU_LOCK_CREAT_ERR); for (i = 0; i < MAXTRIES; i++) { @@ -89,7 +87,7 @@ uu_lock(const char *tty_name) * check to see if the process holding the lock * still exists */ - if ((fd = open(lckname, O_RDONLY)) < 0) + if ((fd = open(lckname, O_RDONLY | O_CLOEXEC)) < 0) GORET(1, UU_LOCK_OPEN_ERR); if ((pid_old = get_pid (fd, &err)) == -1) @@ -129,16 +127,16 @@ int uu_lock_txfr(const char *tty_name, pid_t pid) { int fd, err; - char lckname[PATH_MAX]; + char lckname[sizeof(_PATH_UUCPLOCK) + NAME_MAX]; snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, tty_name); - if ((fd = open(lckname, O_RDWR)) < 0) + if ((fd = open(lckname, O_RDWR | O_CLOEXEC)) < 0) return UU_LOCK_OWNER_ERR; if (get_pid(fd, &err) != getpid()) err = UU_LOCK_OWNER_ERR; else { - lseek(fd, 0, SEEK_SET); + lseek(fd, (off_t)0, SEEK_SET); err = put_pid(fd, pid) ? 0 : UU_LOCK_WRITE_ERR; } close(fd); @@ -149,7 +147,7 @@ uu_lock_txfr(const char *tty_name, pid_t pid) int uu_unlock(const char *tty_name) { - char tbuf[PATH_MAX]; + char tbuf[sizeof(_PATH_UUCPLOCK) + NAME_MAX]; (void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, tty_name); return unlink(tbuf); @@ -203,7 +201,7 @@ put_pid(int fd, pid_t pid) int len; len = sprintf (buf, "%10d\n", (int)pid); - return write (fd, buf, len) == len; + return write (fd, buf, (size_t)len) == len; } static pid_t @@ -216,7 +214,7 @@ get_pid(int fd, int *err) bytes_read = read (fd, buf, sizeof (buf) - 1); if (bytes_read > 0) { buf[bytes_read] = '\0'; - pid = strtol (buf, NULL, 10); + pid = (pid_t)strtol (buf, (char **) NULL, 10); } else { pid = -1; *err = bytes_read ? errno : EINVAL; diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc index 304541abc3..d61dd2f604 100644 --- a/sbin/devd/devd.cc +++ b/sbin/devd/devd.cc @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sbin/devd/devd.cc,v 1.33 2006/09/17 22:49:26 ru Exp $ - * $DragonFly: src/sbin/devd/devd.cc,v 1.1 2008/10/03 00:26:21 hasso Exp $ + */ /* @@ -80,6 +80,7 @@ static const char nomatch = '?'; static const char attach = '+'; static const char detach = '-'; +static struct pidfh *pfh; int Dflag; int dflag; int nflag; @@ -154,18 +155,18 @@ action::~action() bool action::do_action(config &c) { - string s = c.expand_string(_cmd); + string s = c.expand_string(_cmd.c_str()); if (Dflag) fprintf(stderr, "Executing '%s'\n", s.c_str()); ::system(s.c_str()); return (true); } -match::match(config &c, const char *var, const char *re) - : _var(var), _re("^") +match::match(config &c, const char *var, const char *re) : + _inv(re[0] == '!'), + _var(var), + _re(c.expand_string(_inv ? re + 1 : re, "^", "$")) { - _re.append(c.expand_string(string(re))); - _re.append("$"); regcomp(&_regex, _re.c_str(), REG_EXTENDED | REG_NOSUB | REG_ICASE); } @@ -180,12 +181,21 @@ match::do_match(config &c) const string &value = c.get_variable(_var); bool retval; + /* + * This function gets called WAY too often to justify calling syslog() + * each time, even at LOG_DEBUG. Because if syslogd isn't running, it + * can consume excessive amounts of systime inside of connect(). Only + * log when we're in -d mode. + */ if (Dflag) fprintf(stderr, "Testing %s=%s against %s\n", _var.c_str(), value.c_str(), _re.c_str()); retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0); - return retval; + if (_inv == 1) + retval = (retval == 0) ? 1 : 0; + + return (retval); } #include @@ -256,7 +266,7 @@ media::do_match(config &c) close(s); } - return retval; + return (retval); } const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_"; @@ -282,6 +292,12 @@ var_list::is_set(const string &var) const void var_list::set_variable(const string &var, const string &val) { + /* + * This function gets called WAY too often to justify calling syslog() + * each time, even at LOG_DEBUG. Because if syslogd isn't running, it + * can consume excessive amounts of systime inside of connect(). Only + * log when we're in -d mode. + */ if (Dflag) fprintf(stderr, "setting %s=%s\n", var.c_str(), val.c_str()); _vars[var] = val; @@ -333,6 +349,7 @@ config::parse_files_in_dir(const char *dirname) parse_one_file(path); } } + closedir(dirp); } class epv_greater { @@ -366,8 +383,37 @@ config::parse(void) void config::open_pidfile() { - if (pidfile(NULL)) - errx(1, "devd already running"); + pid_t otherpid; + + if (_pidfile.empty()) + return; + pfh = pidfile_open(_pidfile.c_str(), 0600, &otherpid); + if (pfh == NULL) { + if (errno == EEXIST) + errx(1, "devd already running, pid: %d", (int)otherpid); + warn("cannot open pid file"); + } +} + +void +config::write_pidfile() +{ + + pidfile_write(pfh); +} + +void +config::close_pidfile() +{ + + pidfile_close(pfh); +} + +void +config::remove_pidfile() +{ + + pidfile_remove(pfh); } void @@ -459,7 +505,7 @@ void config::expand_one(const char *&src, string &dst) { int count; - string buffer, varstr; + string buffer; src++; // $$ -> $ @@ -496,25 +542,37 @@ config::expand_one(const char *&src, string &dst) do { buffer += *src++; } while (is_id_char(*src)); - buffer.append("", 1); - varstr = get_variable(buffer.c_str()); - dst.append(varstr); + dst.append(get_variable(buffer)); } const string -config::expand_string(const string &s) +config::expand_string(const char *src, const char *prepend, const char *append) { - const char *src; + const char *var_at; string dst; - src = s.c_str(); - while (*src) { - if (*src == '$') + /* + * 128 bytes is enough for 2427 of 2438 expansions that happen + * while parsing config files, as tested on 2013-01-30. + */ + dst.reserve(128); + + if (prepend != NULL) + dst = prepend; + + for (;;) { + var_at = strchr(src, '$'); + if (var_at == NULL) { + dst.append(src); + break; + } + dst.append(src, var_at - src); + src = var_at; expand_one(src, dst); - else - dst.append(src++, 1); } - dst.append("", 1); + + if (append != NULL) + dst.append(append); return (dst); } @@ -608,7 +666,7 @@ config::find_and_execute(char type) } - + static void process_event(char *buffer) { @@ -632,9 +690,13 @@ process_event(char *buffer) if (sp == NULL) return; /* Can't happen? */ *sp++ = '\0'; + while (isspace(*sp)) + sp++; if (strncmp(sp, "at ", 3) == 0) sp += 3; sp = cfg.set_vars(sp); + while (isspace(*sp)) + sp++; if (strncmp(sp, "on ", 3) == 0) cfg.set_variable("bus", sp + 3); break; @@ -645,9 +707,13 @@ process_event(char *buffer) return; /* Can't happen? */ *sp++ = '\0'; cfg.set_variable("device-name", buffer); + while (isspace(*sp)) + sp++; if (strncmp(sp, "at ", 3) == 0) sp += 3; sp = cfg.set_vars(sp); + while (isspace(*sp)) + sp++; if (strncmp(sp, "on ", 3) == 0) cfg.set_variable("bus", sp + 3); break; @@ -739,8 +805,10 @@ event_loop(void) if (rv == 0) { if (Dflag) fprintf(stderr, "Calling daemon\n"); - daemon(0, 0); + cfg.remove_pidfile(); cfg.open_pidfile(); + daemon(0, 0); + cfg.write_pidfile(); once++; } } @@ -774,7 +842,7 @@ event_loop(void) } close(fd); } - + /* * functions that the parser uses. */ @@ -859,7 +927,7 @@ set_variable(const char *var, const char *val) free(const_cast(val)); } - + static void gensighand(int) @@ -921,10 +989,9 @@ main(int argc, char **argv) cfg.parse(); if (!dflag && nflag) { - if (Dflag) - fprintf(stderr, "Calling daemon\n"); - daemon(0, 0); cfg.open_pidfile(); + daemon(0, 0); + cfg.write_pidfile(); } signal(SIGPIPE, SIG_IGN); signal(SIGHUP, gensighand); diff --git a/sbin/devd/devd.hh b/sbin/devd/devd.hh index c2d52fc354..f32e7b380c 100644 --- a/sbin/devd/devd.hh +++ b/sbin/devd/devd.hh @@ -23,8 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sbin/devd/devd.hh,v 1.5 2007/12/21 01:00:04 imp Exp $ - * $DragonFly: src/sbin/devd/devd.hh,v 1.1 2008/10/03 00:26:21 hasso Exp $ + * $FreeBSD: head/sbin/devd/devd.hh 247760 2013-03-04 02:21:24Z eadler $ */ #ifndef DEVD_HH @@ -91,6 +90,7 @@ public: virtual bool do_match(config &); virtual bool do_action(config &) { return true; } private: + bool _inv; std::string _var; std::string _re; regex_t _regex; @@ -144,7 +144,7 @@ private: class config { public: - config() : _pidfile("") { push_var_table(); } + config() { push_var_table(); } virtual ~config() { reset(); } void add_attach(int, event_proc *); void add_detach(int, event_proc *); @@ -154,6 +154,7 @@ public: void set_pidfile(const char *); void reset(); void parse(); + void close_pidfile(); void open_pidfile(); void write_pidfile(); void remove_pidfile(); @@ -161,7 +162,8 @@ public: void pop_var_table(); void set_variable(const char *var, const char *val); const std::string &get_variable(const std::string &var); - const std::string expand_string(const std::string &var); + const std::string expand_string(const char * var, + const char * prepend = NULL, const char * append = NULL); char *set_vars(char *); void find_and_execute(char); protected: diff --git a/usr.sbin/apmd/apmd.c b/usr.sbin/apmd/apmd.c index 7f9edcefe6..4af0a5b4c0 100644 --- a/usr.sbin/apmd/apmd.c +++ b/usr.sbin/apmd/apmd.c @@ -624,6 +624,7 @@ main(int ac, char* av[]) int daemonize = 1; char *prog; int logopt = LOG_NDELAY | LOG_PID; + struct pidfh *pfh = NULL; while ((ch = getopt(ac, av, "df:v")) != -1) { switch (ch) { @@ -642,6 +643,7 @@ main(int ac, char* av[]) } } + pfh = pidfile_open(NULL, 600, NULL); if (daemonize) daemon(0, 0); @@ -671,7 +673,7 @@ main(int ac, char* av[]) } restart(); - pidfile(NULL); + pidfile_write(pfh); event_loop(); exit(EXIT_SUCCESS); } diff --git a/usr.sbin/authpf/authpf.c b/usr.sbin/authpf/authpf.c index 690c61d544..423d094879 100644 --- a/usr.sbin/authpf/authpf.c +++ b/usr.sbin/authpf/authpf.c @@ -1,29 +1,21 @@ -/* $OpenBSD: authpf.c,v 1.104 2007/02/24 17:35:08 beck Exp $ */ -/* $DragonFly: src/usr.sbin/authpf/authpf.c,v 1.2 2004/12/18 22:48:02 swildner Exp $ */ +/* $OpenBSD: authpf.c,v 1.112 2009/01/10 19:08:53 miod Exp $ */ /* * Copyright (C) 1998 - 2007 Bob Beck (beck@openbsd.org). * - * 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. + * 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. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * 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. + * + * $FreeBSD: head/contrib/pf/authpf/authpf.c 223637 2011-06-28 11:57:25Z bz $ */ #include @@ -95,12 +87,12 @@ main(int argc __unused, char **argv __unused) char *cp; gid_t gid; uid_t uid; - char *shell; + const char *shell; login_cap_t *lc; config = fopen(PATH_CONFFILE, "r"); if (config == NULL) { - syslog(LOG_ERR, "can not open %s (%m)", PATH_CONFFILE); + syslog(LOG_ERR, "cannot open %s (%m)", PATH_CONFFILE); exit(1); } @@ -150,18 +142,16 @@ main(int argc __unused, char **argv __unused) else shell = pw->pw_shell; - login_close(lc); + if (strcmp(shell, PATH_AUTHPF_SHELL)) { syslog(LOG_ERR, "wrong shell for user %s, uid %u", pw->pw_name, pw->pw_uid); - if (shell != pw->pw_shell) - free(shell); + login_close(lc); goto die; } - if (shell != pw->pw_shell) - free(shell); + login_close(lc); /* * Paranoia, but this data _does_ come from outside authpf, and @@ -173,11 +163,11 @@ main(int argc __unused, char **argv __unused) } if ((n = snprintf(rulesetname, sizeof(rulesetname), "%s(%ld)", - luser, (long)getpid())) < 0 || n >= (int)sizeof(rulesetname)) { + luser, (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) { syslog(LOG_INFO, "%s(%ld) too large, ruleset name will be %ld", luser, (long)getpid(), (long)getpid()); if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld", - (long)getpid())) < 0 || n >= (int)sizeof(rulesetname)) { + (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) { syslog(LOG_ERR, "pid too large for ruleset name"); goto die; } @@ -244,9 +234,9 @@ main(int argc __unused, char **argv __unused) } /* - * we try to kill the previous process and acquire the lock + * We try to kill the previous process and acquire the lock * for 10 seconds, trying once a second. if we can't after - * 10 attempts we log an error and give up + * 10 attempts we log an error and give up. */ if (++lockcnt > 10) { syslog(LOG_ERR, "cannot kill previous authpf (pid %d)", @@ -362,6 +352,8 @@ read_config(FILE *f) } i++; len = strlen(buf); + if (len == 0) + continue; if (buf[len - 1] != '\n' && !feof(f)) { syslog(LOG_ERR, "line %d too long in %s", i, PATH_CONFFILE); diff --git a/usr.sbin/battd/battd.c b/usr.sbin/battd/battd.c index 441934234b..0cccc2da57 100644 --- a/usr.sbin/battd/battd.c +++ b/usr.sbin/battd/battd.c @@ -354,9 +354,12 @@ main(int argc, char **argv) #ifdef DEBUG if (f_debug == 0) { #endif + struct pidfh *pfh = NULL; + + pfh = pidfile_open(NULL, 600, NULL); if (daemon(0, 0) == -1) err(1, "daemon failed"); - pidfile(NULL); + pidfile_write(pfh); #ifdef DEBUG } #endif diff --git a/usr.sbin/bthcid/bthcid.c b/usr.sbin/bthcid/bthcid.c index 5d689e73bd..32a475fc3f 100644 --- a/usr.sbin/bthcid/bthcid.c +++ b/usr.sbin/bthcid/bthcid.c @@ -62,6 +62,8 @@ main(int argc, char *argv[]) mode_t mode; struct kevent change; struct timespec timeout = { 0, 0 }; + struct pidfh *pfh = NULL; + const char *pidfile = NULL; bdaddr_copy(&bdaddr, BDADDR_ANY); mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; @@ -129,9 +131,13 @@ main(int argc, char *argv[]) exit(EXIT_FAILURE); } - if (detach && pidfile(NULL) < 0) { - syslog(LOG_ERR, "Could not create PID file: %m"); - exit(EXIT_FAILURE); + if (detach) { + pfh = pidfile_open(pidfile, 600, NULL); + if (pfh == NULL) { + syslog(LOG_ERR, "Could not create PID file: %m"); + exit(EXIT_FAILURE); + } + pidfile_write(pfh); } read_config_file(); diff --git a/usr.sbin/pflogd/pflogd.c b/usr.sbin/pflogd/pflogd.c index 86a43af87b..f0f70ebc93 100644 --- a/usr.sbin/pflogd/pflogd.c +++ b/usr.sbin/pflogd/pflogd.c @@ -566,6 +566,7 @@ main(int argc, char **argv) int ch, np, ret, Xflag = 0; pcap_handler phandler = dump_packet; const char *errstr = NULL; + struct pidfh *pfh = NULL; char *pidf = NULL; ret = 0; @@ -625,11 +626,12 @@ main(int argc, char **argv) if (!Debug) { openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON); + pfh = pidfile_open(pidf, 0600, NULL); if (daemon(0, 0)) { logmsg(LOG_WARNING, "Failed to become daemon: %s", strerror(errno)); } - pidfile(pidf); + pidfile_write(pfh); } umask(S_IRWXG | S_IRWXO); diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c index ab23d6c912..d7c00cef71 100644 --- a/usr.sbin/rwhod/rwhod.c +++ b/usr.sbin/rwhod/rwhod.c @@ -227,8 +227,10 @@ main(int argc, char *argv[]) if (argc > 0) usage(); #ifndef DEBUG + struct pidfh *pfh = NULL; + pfh = pidfile_open(NULL, 600, NULL); daemon(1, 0); - pidfile(NULL); + pidfile_write(pfh); #endif signal(SIGHUP, hup); openlog("rwhod", LOG_PID, LOG_DAEMON); diff --git a/usr.sbin/syslogd/Makefile b/usr.sbin/syslogd/Makefile index 29a488ecfa..2572247065 100644 --- a/usr.sbin/syslogd/Makefile +++ b/usr.sbin/syslogd/Makefile @@ -1,19 +1,16 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 -# $FreeBSD: src/usr.sbin/syslogd/Makefile,v 1.14 2008/12/17 16:51:40 obrien Exp $ -# $DragonFly: src/usr.sbin/syslogd/Makefile,v 1.3 2004/08/09 20:11:19 dillon Exp $ +# $FreeBSD: head/usr.sbin/syslogd/Makefile 211055 2010-08-08 02:45:14Z imp $ -.PATH: ${.CURDIR}/../../usr.bin/wall ${.CURDIR}/../nscd ${.CURDIR}/../../usr.bin/who +.PATH: ${.CURDIR}/../../usr.bin/wall PROG= syslogd MAN= syslog.conf.5 syslogd.8 -SRCS= pidfile.c syslogd.c ttymsg.c utmpentry.c +SRCS= syslogd.c ttymsg.c DPADD= ${LIBUTIL} LDADD= -lutil CFLAGS+= -DINET6 CFLAGS+= -I${.CURDIR}/../../usr.bin/wall -CFLAGS+= -I${.CURDIR}/../../usr.bin/who -DSUPPORT_UTMP -DSUPPORT_UTMPX - .include diff --git a/usr.sbin/syslogd/pathnames.h b/usr.sbin/syslogd/pathnames.h index 2dc61a8d1b..29bbb538bd 100644 --- a/usr.sbin/syslogd/pathnames.h +++ b/usr.sbin/syslogd/pathnames.h @@ -10,11 +10,7 @@ * 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 the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 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. * @@ -31,6 +27,7 @@ * SUCH DAMAGE. * * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + * $FreeBSD: head/usr.sbin/syslogd/pathnames.h 133249 2004-08-07 04:28:56Z imp $ */ #include diff --git a/usr.sbin/syslogd/syslog.conf.5 b/usr.sbin/syslogd/syslog.conf.5 index 5fa878c909..51fb70dfda 100644 --- a/usr.sbin/syslogd/syslog.conf.5 +++ b/usr.sbin/syslogd/syslog.conf.5 @@ -26,10 +26,9 @@ .\" SUCH DAMAGE. .\" .\" @(#)syslog.conf.5 8.1 (Berkeley) 6/9/93 -.\" $FreeBSD: src/usr.sbin/syslogd/syslog.conf.5,v 1.46 2008/12/23 17:39:24 trhodes Exp $ -.\" $DragonFly: src/usr.sbin/syslogd/syslog.conf.5,v 1.10 2008/04/20 21:14:39 swildner Exp $ +.\" $FreeBSD: head/usr.sbin/syslogd/syslog.conf.5 240409 2012-09-12 16:58:42Z eadler $ .\" -.Dd December 23, 2008 +.Dd September 12, 2012 .Dt SYSLOG.CONF 5 .Os .Sh NAME @@ -323,7 +322,7 @@ A pathname (beginning with a leading slash). Selected messages are appended to the file. .Pp To ensure that kernel messages are written to disk promptly, -.Xr syslogd 8 +.Nm calls .Xr fsync 2 after writing messages from the kernel. @@ -348,6 +347,14 @@ If a port number is added after a colon .Pq Ql :\& then that port will be used as the destination port rather than the usual syslog port. +IPv6 addresses can be used +by surrounding the address portion with +square brackets +.Po +.Ql [\& +and +.Ql ]\& +.Pc . .It A comma separated list of users. Selected messages are written to those users @@ -356,14 +363,6 @@ if they are logged in. An asterisk. Selected messages are written to all logged-in users. .It -A percent sign -.Pq Dq \&% , -followed by a pathname (beginning with a leading slash). Selected messages -are written to a circular log file. -See -.Xr clog 8 -for a discussion of circular log files. -.It A vertical bar .Pq Dq \&| , followed by a command to pipe the selected @@ -485,16 +484,16 @@ uucp,news.crit /var/log/spoolerr # Pipe all authentication messages to a filter. auth.* |exec /usr/local/sbin/authfilter -# Save ftpd transactions along with mail and news -!ftpd -*.* /var/log/spoolerr - # Log all security messages to a separate file. security.* /var/log/security # Log all writes to /dev/console to a separate file. console.* /var/log/console.log +# Save ftpd transactions along with mail and news +!ftpd +*.* /var/log/spoolerr + # Log ipfw messages without syncing after every message. !ipfw *.* -/var/log/ipfw @@ -521,7 +520,6 @@ implement the same set of facilities. The facilities authpriv, cron, ftp, and ntp that are known to this implementation might be absent on the target system. -Even worse, DEC -.Ux -uses facility number 10 (which is authpriv in this implementation) to +Even worse, DEC UNIX uses +facility number 10 (which is authpriv in this implementation) to log events for their AdvFS file system. diff --git a/usr.sbin/syslogd/syslogd.8 b/usr.sbin/syslogd/syslogd.8 index 1742ede1ec..eef8428e13 100644 --- a/usr.sbin/syslogd/syslogd.8 +++ b/usr.sbin/syslogd/syslogd.8 @@ -26,7 +26,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)syslogd.8 8.1 (Berkeley) 6/6/93 -.\" $FreeBSD: src/usr.sbin/syslogd/syslogd.8,v 1.64 2008/12/07 18:45:30 trhodes Exp $ +.\" $FreeBSD: head/usr.sbin/syslogd/syslogd.8 236509 2012-06-03 11:29:48Z joel $ .\" .Dd May 13, 2008 .Dt SYSLOGD 8 @@ -36,7 +36,7 @@ .Nd log systems messages .Sh SYNOPSIS .Nm -.Op Fl 468ACcdknosuv +.Op Fl 468ACcdkNnosTuv .Op Fl a Ar allowed_peer .Op Fl b Ar bind_address .Op Fl f Ar config_file @@ -171,10 +171,29 @@ The options are ignored if the .Fl s option is also specified. -.It Fl b Ar bind_address -Specify one specific IP address or hostname to bind to. -If a hostname is specified, -the IPv4 or IPv6 address which corresponds to it is used. +.It Xo +.Fl b +.Sm off +.Ar bind_address Op : Ar service +.Sm on +.Xc +.It Xo +.Fl b +.Sm off +.Li : Ar service +.Sm on +.Xc +Bind to a specific address and/or port. +The address can be specified as a hostname, +and the port as a service name. +If an IPv6 address is specified, it should be enclosed with +.Ql \&[ +and +.Ql \&] . +The default +.Ar service +is +.Ql syslog . .It Fl C Create log files that do not exist (permission is set to .Li 0600 ) . @@ -208,6 +227,13 @@ facility is reserved for messages read directly from Select the number of minutes between .Dq mark messages; the default is 20 minutes. +.It Fl N +Disable binding on UDP sockets. RFC 3164 recommends that outgoing +syslogd messages should originate from the privileged port, this +option +.Em disables +the recommended behavior. This option inherits +.Fl s . .It Fl n Disable dns query for every request. .It Fl o diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c index 9e574747b2..7f77fbcc0a 100644 --- a/usr.sbin/syslogd/syslogd.c +++ b/usr.sbin/syslogd/syslogd.c @@ -27,8 +27,7 @@ * SUCH DAMAGE. * * @(#)syslogd.c 8.3 (Berkeley) 4/4/94 - * $FreeBSD: src/usr.sbin/syslogd/syslogd.c,v 1.163 2008/12/19 18:27:51 delphij Exp $ - * $DragonFly: src/usr.sbin/syslogd/syslogd.c,v 1.6 2007/08/09 02:17:46 dillon Exp $ + * $FreeBSD: head/usr.sbin/syslogd/syslogd.c 258077 2013-11-13 01:04:02Z ian $ */ /* @@ -55,7 +54,6 @@ * by Peter da Silva. * -u and -v by Harlan Stenn. * Priority comparison code by Harlan Stenn. - * Ring buffer code by Jeff Wheelhouse. */ #define MAXLINE 1024 /* maximum line length */ @@ -64,9 +62,11 @@ #define DEFSPRI (LOG_KERN|LOG_CRIT) #define TIMERINTVL 30 /* interval for checking flush, mark */ #define TTYMSGTIME 1 /* timeout passed to ttymsg */ +#define RCVBUF_MINSIZE (80 * 1024) /* minimum size of dgram rcv buffer */ #include #include +#include #include #include #include @@ -76,7 +76,6 @@ #include #include #include -#include #include #include @@ -96,12 +95,10 @@ #include #include #include -#include "utmpentry.h" +#include #include "pathnames.h" #include "ttymsg.h" -#include "../clog/clog.h" -#include "../nscd/pidfile.h" #define SYSLOG_NAMES #include @@ -109,7 +106,6 @@ const char *ConfFile = _PATH_LOGCONF; const char *PidFile = _PATH_LOGPID; const char ctty[] = _PATH_CONSOLE; -const char ring_magic[] = "CLOG"; #define dprintf if (Debug) printf @@ -164,7 +160,7 @@ struct filed { #define PRI_GT 0x4 char *f_program; /* program this applies to */ union { - char f_uname[MAXUNAMES][32+1]; + char f_uname[MAXUNAMES][MAXLOGNAME]; struct { char f_hname[MAXHOSTNAMELEN]; struct addrinfo *f_addr; @@ -175,11 +171,6 @@ struct filed { char f_pname[MAXPATHLEN]; pid_t f_pid; } f_pipe; - struct { - char f_rname[MAXPATHLEN]; - struct clog_footer *f_footer; - size_t f_size; - } f_ring; } f_un; char f_prevline[MAXSVLINE]; /* last message logged */ char f_lasttime[16]; /* time of last occurrence */ @@ -258,12 +249,10 @@ int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ #define F_USERS 5 /* list of users */ #define F_WALL 6 /* everyone logged on */ #define F_PIPE 7 /* pipe to program */ -#define F_RING 8 /* ring buffer (circular log) */ -const char *TypeNames[] = { +const char *TypeNames[8] = { "UNUSED", "FILE", "TTY", "CONSOLE", - "FORW", "USERS", "WALL", "PIPE", - "RING" + "FORW", "USERS", "WALL", "PIPE" }; static struct filed *Files; /* Log files that we write to */ @@ -278,6 +267,7 @@ static int fklog = -1; /* /dev/klog */ static int Initialized; /* set when we have initialized ourselves */ static int MarkInterval = 20 * 60; /* interval between marks in seconds */ static int MarkSeq; /* mark sequence number */ +static int NoBind; /* don't bind() as suggested by RFC 3164 */ static int SecureMode; /* when true, receive only unix domain socks */ #ifdef INET6 static int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */ @@ -311,13 +301,13 @@ static void cfline(const char *, struct filed *, static const char *cvthname(struct sockaddr *); static void deadq_enter(pid_t, const char *); static int deadq_remove(pid_t); -static int decode(const char *, CODE *); +static int decode(const char *, const CODE *); static void die(int); static void dodie(int); static void dofsync(void); static void domark(int); static void fprintlog(struct filed *, int, const char *); -static int *socksetup(int, const char *); +static int *socksetup(int, char *); static void init(int); static void logerror(const char *); static void logmsg(int, const char *, const char *, int); @@ -327,8 +317,6 @@ static int skip_message(const char *, const char *, int); static void printline(const char *, char *, int); static void printsys(char *); static int p_open(const char *, pid_t *); -ssize_t rbwrite(struct filed *, char *, size_t); -ssize_t rbwritev(struct filed *, struct iovec *, int); static void readklog(void); static void reapchild(int); static void usage(void); @@ -337,7 +325,7 @@ static void unmapped(struct sockaddr *); static void wallmsg(struct filed *, struct iovec *, const int iovlen); static int waitdaemon(int, int, int); static void timedout(int); -static void double_rbuf(int); +static void increase_rcvbuf(int); int main(int argc, char *argv[]) @@ -347,7 +335,8 @@ main(int argc, char *argv[]) struct sockaddr_storage frominet; fd_set *fdsr = NULL; char line[MAXLINE + 1]; - const char *bindhostname, *hname; + char *bindhostname; + const char *hname; struct timeval tv, *tvp; struct sigaction sact; struct funix *fx, *fx1; @@ -356,7 +345,7 @@ main(int argc, char *argv[]) socklen_t len; bindhostname = NULL; - while ((ch = getopt(argc, argv, "468Aa:b:cCdf:kl:m:nop:P:sS:Tuv")) + while ((ch = getopt(argc, argv, "468Aa:b:cCdf:kl:m:nNop:P:sS:Tuv")) != -1) switch (ch) { case '4': @@ -435,6 +424,10 @@ main(int argc, char *argv[]) case 'm': /* mark interval */ MarkInterval = atoi(optarg) * 60; break; + case 'N': + NoBind = 1; + SecureMode = 1; + break; case 'n': resolve = 0; break; @@ -494,12 +487,12 @@ main(int argc, char *argv[]) endservent(); consfile.f_type = F_CONSOLE; - strlcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1, + (void)strlcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1, sizeof(consfile.f_un.f_fname)); - strlcpy(bootfile, getbootfile(), sizeof(bootfile)); - signal(SIGTERM, dodie); - signal(SIGINT, Debug ? dodie : SIG_IGN); - signal(SIGQUIT, Debug ? dodie : SIG_IGN); + (void)strlcpy(bootfile, getbootfile(), sizeof(bootfile)); + (void)signal(SIGTERM, dodie); + (void)signal(SIGINT, Debug ? dodie : SIG_IGN); + (void)signal(SIGQUIT, Debug ? dodie : SIG_IGN); /* * We don't want the SIGCHLD and SIGHUP handlers to interfere * with each other; they are likely candidates for being called @@ -511,10 +504,10 @@ main(int argc, char *argv[]) sact.sa_handler = reapchild; sact.sa_mask = mask; sact.sa_flags = SA_RESTART; - sigaction(SIGCHLD, &sact, NULL); - signal(SIGALRM, domark); - signal(SIGPIPE, SIG_IGN); /* We'll catch EPIPE instead. */ - alarm(TIMERINTVL); + (void)sigaction(SIGCHLD, &sact, NULL); + (void)signal(SIGALRM, domark); + (void)signal(SIGPIPE, SIG_IGN); /* We'll catch EPIPE instead. */ + (void)alarm(TIMERINTVL); TAILQ_INIT(&deadq_head); @@ -522,15 +515,15 @@ main(int argc, char *argv[]) #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) #endif STAILQ_FOREACH_MUTABLE(fx, &funixes, next, fx1) { - unlink(fx->name); + (void)unlink(fx->name); memset(&sunx, 0, sizeof(sunx)); sunx.sun_family = AF_LOCAL; - strlcpy(sunx.sun_path, fx->name, sizeof(sunx.sun_path)); + (void)strlcpy(sunx.sun_path, fx->name, sizeof(sunx.sun_path)); fx->s = socket(PF_LOCAL, SOCK_DGRAM, 0); if (fx->s < 0 || bind(fx->s, (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 || chmod(fx->name, fx->mode) < 0) { - snprintf(line, sizeof line, + (void)snprintf(line, sizeof line, "cannot create %s", fx->name); logerror(line); dprintf("cannot create %s (%d)\n", fx->name, errno); @@ -540,8 +533,8 @@ main(int argc, char *argv[]) STAILQ_REMOVE(&funixes, fx, funix, next); continue; } - double_rbuf(fx->s); } + increase_rcvbuf(fx->s); } if (SecureMode <= 1) finet = socksetup(family, bindhostname); @@ -579,7 +572,7 @@ main(int argc, char *argv[]) sact.sa_handler = init; sact.sa_mask = mask; sact.sa_flags = SA_RESTART; - sigaction(SIGHUP, &sact, NULL); + (void)sigaction(SIGHUP, &sact, NULL); tvp = &tv; tv.tv_sec = tv.tv_usec = 0; @@ -918,7 +911,7 @@ logmsg(int pri, const char *msg, const char *from, int flags) msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') flags |= ADDDATE; - time(&now); + (void)time(&now); if (flags & ADDDATE) { timestamp = ctime(&now) + 4; } else { @@ -941,7 +934,7 @@ logmsg(int pri, const char *msg, const char *from, int flags) /* Check maximum facility number. */ if (fac > LOG_NFACILITIES) { - sigsetmask(omask); + (void)sigsetmask(omask); return; } @@ -974,12 +967,12 @@ logmsg(int pri, const char *msg, const char *from, int flags) f->f_file = open(ctty, O_WRONLY | O_NONBLOCK, 0); if (f->f_file >= 0) { - strlcpy(f->f_lasttime, timestamp, + (void)strlcpy(f->f_lasttime, timestamp, sizeof(f->f_lasttime)); fprintlog(f, flags, msg); - close(f->f_file); + (void)close(f->f_file); } - sigsetmask(omask); + (void)sigsetmask(omask); return; } for (f = Files; f; f = f->f_next) { @@ -1014,7 +1007,7 @@ logmsg(int pri, const char *msg, const char *from, int flags) (flags & MARK) == 0 && msglen == f->f_prevlen && f->f_prevline && !strcmp(msg, f->f_prevline) && !strcasecmp(from, f->f_prevhost)) { - strlcpy(f->f_lasttime, timestamp, + (void)strlcpy(f->f_lasttime, timestamp, sizeof(f->f_lasttime)); f->f_prevcount++; dprintf("msg repeated %d times, %ld sec of %d\n", @@ -1027,22 +1020,23 @@ logmsg(int pri, const char *msg, const char *from, int flags) * in the future. */ if (now > REPEATTIME(f)) { - fprintlog(f, flags, NULL); + fprintlog(f, flags, (char *)NULL); BACKOFF(f); } } else { /* new line, save it */ if (f->f_prevcount) - fprintlog(f, 0, NULL); + fprintlog(f, 0, (char *)NULL); f->f_repeatcount = 0; f->f_prevpri = pri; - strlcpy(f->f_lasttime, timestamp, + (void)strlcpy(f->f_lasttime, timestamp, sizeof(f->f_lasttime)); - strlcpy(f->f_prevhost, from, sizeof(f->f_prevhost)); + (void)strlcpy(f->f_prevhost, from, + sizeof(f->f_prevhost)); if (msglen < MAXSVLINE) { f->f_prevlen = msglen; - strlcpy(f->f_prevline, msg, sizeof(f->f_prevline)); - fprintlog(f, flags, NULL); + (void)strlcpy(f->f_prevline, msg, sizeof(f->f_prevline)); + fprintlog(f, flags, (char *)NULL); } else { f->f_prevline[0] = 0; f->f_prevlen = 0; @@ -1050,7 +1044,7 @@ logmsg(int pri, const char *msg, const char *from, int flags) } } } - sigsetmask(omask); + (void)sigsetmask(omask); } static void @@ -1062,7 +1056,7 @@ dofsync(void) if ((f->f_type == F_FILE) && (f->f_flags & FFLAG_NEEDSYNC)) { f->f_flags &= ~FFLAG_NEEDSYNC; - fsync(f->f_file); + (void)fsync(f->f_file); } } } @@ -1090,7 +1084,8 @@ fprintlog(struct filed *f, int flags, const char *msg) v->iov_len = snprintf(greetings, sizeof greetings, "\r\n\7Message from syslogd@%s at %.24s ...\r\n", f->f_prevhost, f->f_lasttime); - if (v->iov_len > 0) + if (v->iov_len >= sizeof greetings) + v->iov_len = sizeof greetings - 1; v++; v->iov_base = nul; v->iov_len = 0; @@ -1114,7 +1109,7 @@ fprintlog(struct filed *f, int flags, const char *msg) char p_n[5]; /* Hollow laugh */ if (LogFacPri > 1) { - CODE *c; + const CODE *c; for (c = facilitynames; c->c_name; c++) { if (c->c_val == fac) { @@ -1232,8 +1227,10 @@ fprintlog(struct filed *f, int flags, const char *msg) switch (errno) { case ENOBUFS: case ENETDOWN: + case ENETUNREACH: case EHOSTUNREACH: case EHOSTDOWN: + case EADDRNOTAVAIL: break; /* case EBADF: */ /* case EACCES: */ @@ -1244,7 +1241,7 @@ fprintlog(struct filed *f, int flags, const char *msg) /* case ENOBUFS: */ /* case ECONNREFUSED: */ default: - dprintf("removing entry\n"); + dprintf("removing entry: errno=%d\n", e); f->f_type = F_UNUSED; break; } @@ -1264,7 +1261,7 @@ fprintlog(struct filed *f, int flags, const char *msg) */ if (errno != ENOSPC) { int e = errno; - close(f->f_file); + (void)close(f->f_file); f->f_type = F_UNUSED; errno = e; logerror(f->f_un.f_fname); @@ -1275,21 +1272,6 @@ fprintlog(struct filed *f, int flags, const char *msg) } break; - case F_RING: - dprintf(" %s\n", f->f_un.f_ring.f_rname); - v->iov_base = lf; - v->iov_len = 1; - if (rbwritev(f, iov, 7) == -1) { - int e = errno; - munmap(f->f_un.f_ring.f_footer, - sizeof(struct clog_footer)); - close(f->f_file); - f->f_type = F_UNUSED; - errno = e; - logerror(f->f_un.f_fname); - } - break; - case F_PIPE: dprintf(" %s\n", f->f_un.f_pipe.f_pname); v->iov_base = lf; @@ -1304,7 +1286,7 @@ fprintlog(struct filed *f, int flags, const char *msg) } if (writev(f->f_file, iov, IOV_SIZE) < 0) { int e = errno; - close(f->f_file); + (void)close(f->f_file); if (f->f_un.f_pipe.f_pid > 0) deadq_enter(f->f_un.f_pipe.f_pid, f->f_un.f_pipe.f_pname); @@ -1355,26 +1337,20 @@ static void wallmsg(struct filed *f, struct iovec *iov, const int iovlen) { static int reenter; /* avoid calling ourselves */ - - struct utmpentry *ep; + struct utmpx *ut; int i; const char *p; if (reenter++) return; - - getutentries(NULL, &ep); - if (ep == NULL) { - logerror("getutentries"); - reenter = 0; - return; - } + setutxent(); /* NOSTRICT */ - for (; ep; ep = ep->next) { - /* We must use strncpy since ut_* may not be NUL terminated. */ + while ((ut = getutxent()) != NULL) { + if (ut->ut_type != USER_PROCESS) + continue; if (f->f_type == F_WALL) { - if ((p = ttymsg(iov, iovlen, ep->line, TTYMSGTIME)) != - NULL) { + if ((p = ttymsg(iov, iovlen, ut->ut_line, + TTYMSGTIME)) != NULL) { errno = 0; /* already in msg */ logerror(p); } @@ -1384,9 +1360,9 @@ wallmsg(struct filed *f, struct iovec *iov, const int iovlen) for (i = 0; i < MAXUNAMES; i++) { if (!f->f_un.f_uname[i][0]) break; - if (!strcmp(f->f_un.f_uname[i], ep->name)) { - if ((p = ttymsg(iov, iovlen, ep->line, TTYMSGTIME)) - != NULL) { + if (!strcmp(f->f_un.f_uname[i], ut->ut_user)) { + if ((p = ttymsg(iov, iovlen, ut->ut_line, + TTYMSGTIME)) != NULL) { errno = 0; /* already in msg */ logerror(p); } @@ -1394,6 +1370,7 @@ wallmsg(struct filed *f, struct iovec *iov, const int iovlen) } } } + endutxent(); reenter = 0; } @@ -1404,7 +1381,7 @@ reapchild(int signo __unused) pid_t pid; struct filed *f; - while ((pid = wait3(&status, WNOHANG, NULL)) > 0) { + while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) { if (!Initialized) /* Don't tell while we are initting. */ continue; @@ -1417,7 +1394,7 @@ reapchild(int signo __unused) for (f = Files; f; f = f->f_next) if (f->f_type == F_PIPE && f->f_un.f_pipe.f_pid == pid) { - close(f->f_file); + (void)close(f->f_file); f->f_un.f_pipe.f_pid = 0; log_deadchild(pid, status, f->f_un.f_pipe.f_pname); @@ -1496,10 +1473,10 @@ logerror(const char *type) return; recursed++; if (errno) - snprintf(buf, + (void)snprintf(buf, sizeof buf, "syslogd: %s: %s", type, strerror(errno)); else - snprintf(buf, sizeof buf, "syslogd: %s", type); + (void)snprintf(buf, sizeof buf, "syslogd: %s", type); errno = 0; dprintf("%s\n", buf); logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); @@ -1519,21 +1496,21 @@ die(int signo) for (f = Files; f != NULL; f = f->f_next) { /* flush any pending output */ if (f->f_prevcount) - fprintlog(f, 0, NULL); + fprintlog(f, 0, (char *)NULL); if (f->f_type == F_PIPE && f->f_un.f_pipe.f_pid > 0) { - close(f->f_file); + (void)close(f->f_file); f->f_un.f_pipe.f_pid = 0; } } Initialized = was_initialized; if (signo) { dprintf("syslogd: exiting on signal %d\n", signo); - snprintf(buf, sizeof(buf), "exiting on signal %d", signo); + (void)snprintf(buf, sizeof(buf), "exiting on signal %d", signo); errno = 0; logerror(buf); } STAILQ_FOREACH(fx, &funixes, next) - unlink(fx->name); + (void)unlink(fx->name); pidfile_remove(pfh); exit(1); @@ -1562,7 +1539,7 @@ init(int signo) * Load hostname (may have changed). */ if (signo != 0) - strlcpy(oldLocalHostName, LocalHostName, + (void)strlcpy(oldLocalHostName, LocalHostName, sizeof(oldLocalHostName)); if (gethostname(LocalHostName, sizeof(LocalHostName))) err(EX_OSERR, "gethostname() failed"); @@ -1580,28 +1557,23 @@ init(int signo) for (f = Files; f != NULL; f = next) { /* flush any pending output */ if (f->f_prevcount) - fprintlog(f, 0, NULL); + fprintlog(f, 0, (char *)NULL); switch (f->f_type) { case F_FILE: case F_FORW: case F_CONSOLE: case F_TTY: - close(f->f_file); + (void)close(f->f_file); break; case F_PIPE: if (f->f_un.f_pipe.f_pid > 0) { - close(f->f_file); + (void)close(f->f_file); deadq_enter(f->f_un.f_pipe.f_pid, f->f_un.f_pipe.f_pname); } f->f_un.f_pipe.f_pid = 0; break; - case F_RING: - munmap(f->f_un.f_ring.f_footer, - sizeof(struct clog_footer)); - close(f->f_file); - break; } next = f->f_next; if (f->f_program) free(f->f_program); @@ -1634,8 +1606,8 @@ init(int signo) * Foreach line in the conf table, open that file. */ f = NULL; - strlcpy(host, "*", sizeof(host)); - strlcpy(prog, "*", sizeof(prog)); + (void)strlcpy(host, "*", sizeof(host)); + (void)strlcpy(prog, "*", sizeof(prog)); while (fgets(cline, sizeof(cline), cf) != NULL) { /* * check for end-of-section, comments, strip off trailing @@ -1656,7 +1628,7 @@ init(int signo) while (isspace(*p)) p++; if ((!*p) || (*p == '*')) { - strlcpy(host, "*", sizeof(host)); + (void)strlcpy(host, "*", sizeof(host)); continue; } if (*p == '@') @@ -1674,7 +1646,7 @@ init(int signo) p++; while (isspace(*p)) p++; if ((!*p) || (*p == '*')) { - strlcpy(prog, "*", sizeof(prog)); + (void)strlcpy(prog, "*", sizeof(prog)); continue; } for (i = 0; i < NAME_MAX; i++) { @@ -1709,7 +1681,7 @@ init(int signo) } /* close the configuration file */ - fclose(cf); + (void)fclose(cf); Initialized = 1; @@ -1743,10 +1715,6 @@ init(int signo) } break; - case F_RING: - printf("%s", f->f_un.f_ring.f_rname); - break; - case F_PIPE: printf("%s", f->f_un.f_pipe.f_pname); break; @@ -1768,7 +1736,7 @@ init(int signo) * Log a change in hostname, but only on a restart. */ if (signo != 0 && strcmp(oldLocalHostName, LocalHostName) != 0) { - snprintf(hostMsg, sizeof(hostMsg), + (void)snprintf(hostMsg, sizeof(hostMsg), "syslogd: hostname changed, \"%s\" to \"%s\"", oldLocalHostName, LocalHostName); logmsg(LOG_SYSLOG|LOG_INFO, hostMsg, LocalHostName, ADDDATE); @@ -1779,7 +1747,7 @@ init(int signo) * the prefix, and if this is *not* a restart. */ if (signo == 0 && !use_bootfile) { - snprintf(bootfileMsg, sizeof(bootfileMsg), + (void)snprintf(bootfileMsg, sizeof(bootfileMsg), "syslogd: kernel boot file is %s", bootfile); logmsg(LOG_KERN|LOG_INFO, bootfileMsg, LocalHostName, ADDDATE); dprintf("%s\n", bootfileMsg); @@ -1797,7 +1765,6 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host) const char *p, *q; char *bp; char buf[MAXLINE], ebuf[100]; - struct stat sb; dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host); @@ -1894,7 +1861,8 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host) pri = decode(buf, prioritynames); if (pri < 0) { - snprintf(ebuf, sizeof ebuf, + errno = 0; + (void)snprintf(ebuf, sizeof ebuf, "unknown priority name \"%s\"", buf); logerror(ebuf); return; @@ -1922,7 +1890,8 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host) } else { i = decode(buf, facilitynames); if (i < 0) { - snprintf(ebuf, sizeof ebuf, + errno = 0; + (void)snprintf(ebuf, sizeof ebuf, "unknown facility name \"%s\"", buf); logerror(ebuf); @@ -1952,6 +1921,7 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host) case '@': { char *tp; + char endkey = ':'; /* * scan forward to see if there is a port defined. * so we can't use strlcpy.. @@ -1960,9 +1930,19 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host) tp = f->f_un.f_forw.f_hname; p++; - while (*p && (*p != ':') && (i-- > 0)) { + /* + * an ipv6 address should start with a '[' in that case + * we should scan for a ']' + */ + if (*p == '[') { + p++; + endkey = ']'; + } + while (*p && (*p != endkey) && (i-- > 0)) { *tp++ = *p++; } + if (endkey == ']' && *p == endkey) + p++; *tp = '\0'; } /* See if we copied a domain and have a port */ @@ -1997,53 +1977,17 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host) f->f_type = F_CONSOLE; else f->f_type = F_TTY; - strlcpy(f->f_un.f_fname, p + sizeof(_PATH_DEV) - 1, + (void)strlcpy(f->f_un.f_fname, p + sizeof(_PATH_DEV) - 1, sizeof(f->f_un.f_fname)); } else { - strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)); + (void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname)); f->f_type = F_FILE; } break; - case '%': - if ((f->f_file = open(p + 1, O_RDWR, 0 )) < 0) { - f->f_type = F_UNUSED; - logerror(p + 1); - break; - } - if (fstat(f->f_file,&sb) < 0) { - close(f->f_file); - f->f_type = F_UNUSED; - logerror(p+1); - break; - } - f->f_un.f_ring.f_footer = - mmap(NULL, sizeof(struct clog_footer), - PROT_READ|PROT_WRITE, MAP_SHARED, - f->f_file, sb.st_size-sizeof(struct clog_footer)); - if (f->f_un.f_ring.f_footer == NULL) { - close(f->f_file); - f->f_type = F_UNUSED; - logerror(p + 1); - break; - } - if (memcmp(&(f->f_un.f_ring.f_footer->cf_magic), MAGIC_CONST, 4) != 0) { - munmap(f->f_un.f_ring.f_footer, - sizeof(struct clog_footer)); - close(f->f_file); - f->f_type = F_UNUSED; - errno = ENODEV; - logerror(p + 1); - break; - } - f->f_un.f_ring.f_size = sb.st_size; - strcpy(f->f_un.f_ring.f_rname, p + 1); - f->f_type = F_RING; - break; - case '|': f->f_un.f_pipe.f_pid = 0; - strlcpy(f->f_un.f_pipe.f_pname, p + 1, + (void)strlcpy(f->f_un.f_pipe.f_pname, p + 1, sizeof(f->f_un.f_pipe.f_pname)); f->f_type = F_PIPE; break; @@ -2056,9 +2000,9 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host) for (i = 0; i < MAXUNAMES && *p; i++) { for (q = p; *q && *q != ','; ) q++; - strncpy(f->f_un.f_uname[i], p, 32); - if ((q - p) > 32) - f->f_un.f_uname[i][32] = '\0'; + (void)strncpy(f->f_un.f_uname[i], p, MAXLOGNAME - 1); + if ((q - p) >= MAXLOGNAME) + f->f_un.f_uname[i][MAXLOGNAME - 1] = '\0'; else f->f_un.f_uname[i][q - p] = '\0'; while (*q == ',' || *q == ' ') @@ -2075,9 +2019,9 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host) * Decode a symbolic name to a numeric value */ static int -decode(const char *name, CODE *codetab) +decode(const char *name, const CODE *codetab) { - CODE *c; + const CODE *c; char *p, buf[40]; if (isdigit(*name)) @@ -2103,7 +2047,7 @@ markit(void) struct filed *f; dq_t q, next; - now = time(NULL); + now = time((time_t *)NULL); MarkSeq += TIMERINTVL; if (MarkSeq >= MarkInterval) { logmsg(LOG_INFO, "-- MARK --", @@ -2116,7 +2060,7 @@ markit(void) dprintf("flush %s: repeated %d times, %d sec.\n", TypeNames[f->f_type], f->f_prevcount, repeatinterval[f->f_repeatcount]); - fprintlog(f, 0, NULL); + fprintlog(f, 0, (char *)NULL); BACKOFF(f); } } @@ -2129,7 +2073,7 @@ markit(void) case 0: /* Already signalled once, try harder now. */ if (kill(q->dq_pid, SIGKILL) != 0) - deadq_remove(q->dq_pid); + (void)deadq_remove(q->dq_pid); break; case 1: @@ -2142,7 +2086,7 @@ markit(void) * drop it from the dead queue). */ if (kill(q->dq_pid, SIGTERM) != 0) - deadq_remove(q->dq_pid); + (void)deadq_remove(q->dq_pid); /* FALLTHROUGH */ default: @@ -2150,7 +2094,7 @@ markit(void) } } MarkSet = 0; - alarm(TIMERINTVL); + (void)alarm(TIMERINTVL); } /* @@ -2192,14 +2136,14 @@ waitdaemon(int nochdir, int noclose, int maxwait) return (-1); if (!nochdir) - chdir("/"); + (void)chdir("/"); if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); + (void)dup2(fd, STDIN_FILENO); + (void)dup2(fd, STDOUT_FILENO); + (void)dup2(fd, STDERR_FILENO); if (fd > 2) - close (fd); + (void)close (fd); } return (getppid()); } @@ -2421,7 +2365,7 @@ validate(struct sockaddr *sa, const char *hname) /* traditional behaviour, allow everything */ return (1); - strlcpy(name, hname, sizeof(name)); + (void)strlcpy(name, hname, sizeof(name)); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; @@ -2520,7 +2464,7 @@ validate(struct sockaddr *sa, const char *hname) static int p_open(const char *prog, pid_t *rpid) { - int pfd[2], nulldesc, i; + int pfd[2], nulldesc; pid_t pid; sigset_t omask, mask; char *argv[4]; /* sh -c cmd NULL */ @@ -2553,7 +2497,7 @@ p_open(const char *prog, pid_t *rpid) } alarm(0); - setsid(); /* Avoid catching SIGHUPs. */ + (void)setsid(); /* Avoid catching SIGHUPs. */ /* * Throw away pending signals, and reset signal @@ -2570,10 +2514,9 @@ p_open(const char *prog, pid_t *rpid) dup2(pfd[0], STDIN_FILENO); dup2(nulldesc, STDOUT_FILENO); dup2(nulldesc, STDERR_FILENO); - for (i = getdtablesize(); i > 2; i--) - close(i); + closefrom(3); - execvp(_PATH_BSHELL, argv); + (void)execvp(_PATH_BSHELL, argv); _exit(255); } @@ -2591,7 +2534,7 @@ p_open(const char *prog, pid_t *rpid) */ if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) { /* This is bad. */ - snprintf(errmsg, sizeof errmsg, + (void)snprintf(errmsg, sizeof errmsg, "Warning: cannot change pipe to PID %d to " "non-blocking behaviour.", (int)pid); @@ -2662,23 +2605,54 @@ log_deadchild(pid_t pid, int status, const char *name) if (code == 0) return; } - snprintf(buf, sizeof buf, + (void)snprintf(buf, sizeof buf, "Logging subprocess %d (%s) exited %s %d.", pid, name, reason, code); logerror(buf); } static int * -socksetup(int af, const char *bindhostname) +socksetup(int af, char *bindhostname) { struct addrinfo hints, *res, *r; + const char *bindservice; + char *cp; int error, maxs, *s, *socks; + /* + * We have to handle this case for backwards compatibility: + * If there are two (or more) colons but no '[' and ']', + * assume this is an inet6 address without a service. + */ + bindservice = "syslog"; + if (bindhostname != NULL) { +#ifdef INET6 + if (*bindhostname == '[' && + (cp = strchr(bindhostname + 1, ']')) != NULL) { + ++bindhostname; + *cp = '\0'; + if (cp[1] == ':' && cp[2] != '\0') + bindservice = cp + 2; + } else { +#endif + cp = strchr(bindhostname, ':'); + if (cp != NULL && strchr(cp + 1, ':') == NULL) { + *cp = '\0'; + if (cp[1] != '\0') + bindservice = cp + 1; + if (cp == bindhostname) + bindhostname = NULL; + } +#ifdef INET6 + } +#endif + } + memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = af; hints.ai_socktype = SOCK_DGRAM; - error = getaddrinfo(bindhostname, "syslog", &hints, &res); + error = getaddrinfo(bindhostname, bindservice, &hints, &res); if (error) { logerror(gai_strerror(error)); errno = 0; @@ -2702,6 +2676,7 @@ socksetup(int af, const char *bindhostname) logerror("socket"); continue; } +#ifdef INET6 if (r->ai_family == AF_INET6) { if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof (on)) < 0) { @@ -2710,19 +2685,31 @@ socksetup(int af, const char *bindhostname) continue; } } +#endif if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { logerror("setsockopt"); close(*s); continue; } + /* + * RFC 3164 recommends that client side message + * should come from the privileged syslogd port. + * + * If the system administrator choose not to obey + * this, we can skip the bind() step so that the + * system will choose a port for us. + */ + if (!NoBind) { if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) { + logerror("bind"); close(*s); - logerror("bind"); continue; } - double_rbuf(*s); + if (!SecureMode) + increase_rcvbuf(*s); + } (*socks)++; s++; @@ -2741,68 +2728,17 @@ socksetup(int af, const char *bindhostname) return (socks); } -ssize_t -rbwritev(struct filed *f, struct iovec *iov, int iovcnt) -{ - int i; - ssize_t out = 0; - ssize_t error; - - for (i = 0; i < iovcnt; i++) { - error = rbwrite(f, iov[i].iov_base, iov[i].iov_len); - if (error == -1) - return (-1); - out += error; - } - return (out); -} - - -ssize_t -rbwrite(struct filed *f, char *buf, size_t nbytes) -{ - size_t maxwrite; - ssize_t error; - ssize_t out; - - maxwrite = f->f_un.f_ring.f_footer->cf_max - - f->f_un.f_ring.f_footer->cf_next; - out = 0; - - f->f_un.f_ring.f_footer->cf_lock = 1; - while (nbytes > 0) { - maxwrite = f->f_un.f_ring.f_footer->cf_max - - f->f_un.f_ring.f_footer->cf_next; - if (maxwrite > nbytes) - maxwrite = nbytes; - error = pwrite(f->f_file, buf, maxwrite, - f->f_un.f_ring.f_footer->cf_next); - if (error == -1) { - f->f_un.f_ring.f_footer->cf_lock = 0; - return (-1); - } - nbytes -= error; - out += error; - buf += error; - f->f_un.f_ring.f_footer->cf_next += error; - if (f->f_un.f_ring.f_footer->cf_next == - f->f_un.f_ring.f_footer->cf_max) { - f->f_un.f_ring.f_footer->cf_next = 0; - f->f_un.f_ring.f_footer->cf_wrap = 1; - } - } - - f->f_un.f_ring.f_footer->cf_lock = 0; - return (out); -} - static void -double_rbuf(int fd) +increase_rcvbuf(int fd) { - socklen_t slen, len; + socklen_t len, slen; + + slen = sizeof(len); if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &slen) == 0) { - len *= 2; - setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, slen); + if (len < RCVBUF_MINSIZE) { + len = RCVBUF_MINSIZE; + setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)); + } } } diff --git a/usr.sbin/sysvipcd/sysvipcd.c b/usr.sbin/sysvipcd/sysvipcd.c index ded2ec87a0..326f2a1f3a 100644 --- a/usr.sbin/sysvipcd/sysvipcd.c +++ b/usr.sbin/sysvipcd/sysvipcd.c @@ -336,6 +336,7 @@ main(int argc, char *argv[]) int c; int error; char *pidfilename = NULL; + struct pidfh *pfh = NULL; sysvd_debug = 0; sysvd_daemon = 1; @@ -374,8 +375,9 @@ main(int argc, char *argv[]) goto out; if (sysvd_daemon == 1) { + pfh = pidfile_open(pidfilename, 600, NULL); daemon(1,0); - pidfile(pidfilename); + pidfile_write(pfh); } daemon_func(); -- 2.41.0