diff options
Diffstat (limited to 'lib/libutil')
43 files changed, 6669 insertions, 0 deletions
diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile new file mode 100644 index 0000000..03f732a --- /dev/null +++ b/lib/libutil/Makefile @@ -0,0 +1,42 @@ +# @(#)Makefile 8.1 (Berkeley) 6/4/93 +# $FreeBSD$ + +LIB= util +SHLIB_MAJOR= 3 +SHLIB_MINOR= 0 +CFLAGS+=-Wall -DLIBC_SCCS -I${.CURDIR} +CFLAGS+=-DINET6 +SRCS= _secure_path.c auth.c fparseln.c login.c login_auth.c \ + login_cap.c login_class.c login_crypt.c login_ok.c login_times.c \ + login_tty.c logout.c logwtmp.c property.c pty.c realhostname.c stub.c \ + trimdomain.c uucplock.c +INCS= libutil.h login_cap.h + +MAN+= login.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 pty.3 \ + login_cap.3 login_class.3 login_times.3 login_ok.3 \ + _secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \ + realhostname_sa.3 trimdomain.3 fparseln.3 +MAN+= login.conf.5 auth.conf.5 +MLINKS+= property.3 properties_read.3 property.3 properties_free.3 +MLINKS+= property.3 property_find.3 +MLINKS+= auth.3 auth_getval.3 +MLINKS+= pty.3 openpty.3 pty.3 forkpty.3 +MLINKS+=login_cap.3 login_getclassbyname.3 login_cap.3 login_close.3 \ + login_cap.3 login_getclass.3 login_cap.3 login_getuserclass.3 \ + login_cap.3 login_getcapstr.3 login_cap.3 login_getcaplist.3 \ + login_cap.3 login_getstyle.3 login_cap.3 login_getcaptime.3 \ + login_cap.3 login_getcapnum.3 login_cap.3 login_getcapsize.3 \ + login_cap.3 login_getcapbool.3 login_cap.3 login_getpath.3 \ + login_cap.3 login_getpwclass.3 login_cap.3 login_setcryptfmt.3 +MLINKS+=login_class.3 setusercontext.3 login_class.3 setclasscontext.3 \ + login_class.3 setclassenvironment.3 login_class.3 setclassresources.3 +MLINKS+=login_times.3 parse_lt.3 login_times.3 in_ltm.3 \ + login_times.3 in_lt.3 login_times.3 in_ltms.3 \ + login_times.3 in_lts.3 +MLINKS+=login_ok.3 auth_ttyok.3 login_ok.3 auth_hostok.3 \ + login_ok.3 auth_timeok.3 +MLINKS+=login_auth.3 auth_checknologin.3 login_auth.3 auth_cat.3 +MLINKS+=uucplock.3 uu_lock.3 uucplock.3 uu_lock_txfr.3 \ + uucplock.3 uu_unlock.3 uucplock.3 uu_lockerr.3 + +.include <bsd.lib.mk> diff --git a/lib/libutil/_secure_path.3 b/lib/libutil/_secure_path.3 new file mode 100644 index 0000000..cd3cc25 --- /dev/null +++ b/lib/libutil/_secure_path.3 @@ -0,0 +1,74 @@ +.\" Copyright (c) 1997 David Nugent <davidn@blaze.net.au> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, is permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice immediately at the beginning of the file, without modification, +.\" this list of conditions, and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. This work was done expressly for inclusion into FreeBSD. Other use +.\" is permitted provided this notation is included. +.\" 4. Absolutely no warranty of function or purpose is made by the author +.\" David Nugent. +.\" 5. Modifications may be freely made to this file providing the above +.\" conditions are met. +.\" +.\" $FreeBSD$ +.\" +.Dd May 2, 1997 +.Os +.Dt _SECURE_PATH 3 +.Sh NAME +.Nm _secure_path +.Nd determine if a file appears to be secure +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In libutil.h +.Ft int +.Fn _secure_path "const char *path" "uid_t uid" "gid_t gid" +.Sh DESCRIPTION +This function does some basic security checking on a given path. +It is intended to be used by processes running with root privileges +in order to decide whether or not to trust the contents of a given +file. +It uses a method often used to detect system compromise. +.Pp +A file is considered +.Sq secure +if it meets the following conditions: +.Bl -enum +.It +The file exists, and is a regular file (not a symlink, device +special or named pipe, etc.), +.It +Is not world writable. +.It +Is owned by the given uid or uid 0, if uid is not -1, +.It +Is not group writable or it has group ownership by the given +gid, if gid is not -1. +.El +.Sh RETURN VALUES +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. +.Xr syslog 3 +is used to log any failure of this function, including the +reason, at LOG_ERR priority. +.Sh BUGS +The checks carried out are rudimentary and no attempt is made +to eliminate race conditions between use of this function and +access to the file referenced. +.Sh SEE ALSO +.Xr lstat 2 , +.Xr syslog 3 +.Sh HISTORY +Code from which this function was derived was contributed to the +.Fx +project by Berkeley Software Design, Inc. diff --git a/lib/libutil/_secure_path.c b/lib/libutil/_secure_path.c new file mode 100644 index 0000000..550a092 --- /dev/null +++ b/lib/libutil/_secure_path.c @@ -0,0 +1,74 @@ +/*- + * Based on code copyright (c) 1995,1997 by + * Berkeley Software Design, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. This work was done expressly for inclusion into FreeBSD. Other use + * is permitted provided this notation is included. + * 4. Absolutely no warranty of function or purpose is made by the authors. + * 5. Modifications may be freely made to this file providing the above + * conditions are met. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> +#include <libutil.h> +#include <stddef.h> +#include <syslog.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) + * 3. Group ownership is given group or is non-group writable + * + * Returns: -2 if file does not exist, + * -1 if security test failure + * 0 otherwise + */ + +int +_secure_path(const char *path, uid_t uid, gid_t gid) +{ + int r = -1; + struct stat sb; + const char *msg = NULL; + + if (lstat(path, &sb) < 0) { + if (errno == ENOENT) /* special case */ + r = -2; /* if it is just missing, skip the log entry */ + else + msg = "%s: cannot stat %s: %m"; + } + else if (!S_ISREG(sb.st_mode)) + msg = "%s: %s is not a regular file"; + else if (sb.st_mode & S_IWOTH) + msg = "%s: %s is world writable"; + else if (uid != -1 && sb.st_uid != uid && sb.st_uid != 0) { + if (uid == 0) + msg = "%s: %s is not owned by root"; + else + msg = "%s: %s is not owned by uid %d"; + } else if (gid != -1 && sb.st_gid != gid && (sb.st_mode & S_IWGRP)) + msg = "%s: %s is group writeable by non-authorised groups"; + else + r = 0; + if (msg != NULL) + syslog(LOG_ERR, msg, "_secure_path", path, uid); + return r; +} diff --git a/lib/libutil/auth.3 b/lib/libutil/auth.3 new file mode 100644 index 0000000..56356e4 --- /dev/null +++ b/lib/libutil/auth.3 @@ -0,0 +1,56 @@ +.\" +.\" Copyright (c) 1998 Jordan Hubbard +.\" +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" " +.Dd October 7, 1998 +.Os +.Dt AUTH_GETVAL 3 +.Sh NAME +.Nm auth_getval +.Nd functions for reading values from +.Pa /etc/auth.conf +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In libutil.h +.Ft char * +.Fn auth_getval "const char *name" +.Sh DESCRIPTION +The function +.Fn auth_getval +returns the value assocated with the field called +.Fa name +or NULL if no such field is found or the auth file cannot be opened. +.Sh SEE ALSO +.Xr properties_free 3 , +.Xr properties_read 3 , +.Xr property_find 3 , +.Xr auth.conf 5 +.Sh FILES +.Pa /etc/auth.conf +contains the name=value pairs looked up by +.Fn auth_getval . diff --git a/lib/libutil/auth.c b/lib/libutil/auth.c new file mode 100644 index 0000000..8f3842e --- /dev/null +++ b/lib/libutil/auth.c @@ -0,0 +1,70 @@ +/* + * Simple authentication database handling code. + * + * Copyright (c) 1998 + * Jordan Hubbard. 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, + * verbatim and that no modifications are made prior to this + * point in the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 HIS PETS 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, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <unistd.h> +#include <syslog.h> +#include <sys/types.h> +#include <paths.h> +#include <fcntl.h> +#include <libutil.h> + +static properties P; + +static int +initauthconf(const char *path) +{ + int fd; + + if (!P) { + if ((fd = open(path, O_RDONLY)) < 0) { + syslog(LOG_ERR, "initauthconf: unable to open file: %s", path); + return 1; + } + P = properties_read(fd); + close(fd); + if (!P) { + syslog(LOG_ERR, "initauthconf: unable to parse file: %s", path); + return 1; + } + } + return 0; +} + +char * +auth_getval(const char *name) +{ + if (!P && initauthconf(_PATH_AUTHCONF)) + return NULL; + else + return property_find(P, name); +} diff --git a/lib/libutil/auth.conf.5 b/lib/libutil/auth.conf.5 new file mode 100644 index 0000000..df1e8f9 --- /dev/null +++ b/lib/libutil/auth.conf.5 @@ -0,0 +1,33 @@ +.\" Copyright (c) 1998 Jordan Hubbard +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, is permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice immediately at the beginning of the file, without modification, +.\" 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. +.\" +.\" $FreeBSD$ +.\" +.Dd October 7, 1998 +.Dt AUTH.CONF 5 +.Os +.Sh NAME +.Nm auth.conf +.Nd authentication capability database +.Sh SYNOPSIS +.Pa /etc/auth.conf +.Sh DESCRIPTION +.Nm +contains various attributes important to the authentication +code, most notably +.Xr kerberos 5 +for the time being. This documentation will be updated as the +.Pa /etc/auth.conf +file, which is very new, evolves. +.Sh SEE ALSO +.Xr auth_getval 3 diff --git a/lib/libutil/fparseln.3 b/lib/libutil/fparseln.3 new file mode 100644 index 0000000..1e8f30e --- /dev/null +++ b/lib/libutil/fparseln.3 @@ -0,0 +1,156 @@ +.\" $NetBSD: fparseln.3,v 1.7 1999/07/02 15:49:12 simonb Exp $ +.\" $FreeBSD$ +.\" +.\" Copyright (c) 1997 Christos Zoulas. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by Christos Zoulas. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd December 1, 1997 +.Dt FPARSELN 3 +.Os +.Sh NAME +.Nm fparseln +.Nd return the next logical line from a stream +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In stdio.h +.In libutil.h +.Ft "char *" +.Fo fparseln +.Fa "FILE *stream" "size_t *len" "size_t *lineno" +.Fa "const char delim[3]" "int flags" +.Fc +.Sh DESCRIPTION +The +.Fn fparseln +function +returns a pointer to the next logical line from the stream referenced by +.Fa stream . +This string is +.Dv NUL +terminated and it is dynamically allocated on each invocation. +It is the +responsibility of the caller to free the pointer. +.Pp +By default, if a character is escaped, both it and the preceding escape +character will be present in the returned string. +Various +.Fa flags +alter this behaviour. +.Pp +The meaning of the arguments is as follows: +.Bl -tag -width "lineno" +.It Fa stream +The stream to read from. +.It Fa len +If not +.Dv NULL , +the length of the string is stored in the memory location to which it +points. +.It Fa lineno +If not +.Dv NULL , +the value of the memory location to which is pointed to, is incremented +by the number of lines actually read from the file. +.It Fa delim +Contains the escape, continuation, and comment characters. +If a character is +.Dv NUL +then processing for that character is disabled. +If +.Dv NULL , +all characters default to values specified below. +The contents of +.Fa delim +is as follows: +.Bl -tag -width "delim[0]" +.It Fa delim[0] +The escape character, which defaults to +.Cm \e , +is used to remove any special meaning from the next character. +.It Fa delim[1] +The continuation character, which defaults to +.Cm \e , +is used to indicate that the next line should be concatenated with the +current one if this character is the last character on the current line +and is not escaped. +.It Fa delim[2] +The comment character, which defaults to +.Cm # , +if not escaped indicates the beginning of a comment that extends until the +end of the current line. +.El +.It Fa flags +If non-zero, alter the operation of +.Fn fparseln . +The various flags, which may be +.Em or Ns -ed +together, are: +.Bl -tag -width "FPARSELN_UNESCCOMM" +.It Dv FPARSELN_UNESCCOMM +Remove escape preceding an escaped comment. +.It Dv FPARSELN_UNESCCONT +Remove escape preceding an escaped continuation. +.It Dv FPARSELN_UNESCESC +Remove escape preceding an escaped escape. +.It Dv FPARSELN_UNESCREST +Remove escape preceding any other character. +.It Dv FPARSELN_UNESCALL +All of the above. +.El +.Pp +.El +.Sh RETURN VALUES +Upon successful completion a pointer to the parsed line is returned; +otherwise, +.Dv NULL +is returned. +.Pp +The +.Fn fparseln +function uses internally +.Xr fgetln 3 , +so all error conditions that apply to +.Xr fgetln 3 , +apply to +.Fn fparseln . +In addition +.Fn fparseln +may set +.Va errno +to +.Er ENOMEM +and return +.Dv NULL +if it runs out of memory. +.Sh SEE ALSO +.Xr fgetln 3 +.Sh HISTORY +The +.Fn fparseln +function first appeared in +.Nx 1.4 . diff --git a/lib/libutil/fparseln.c b/lib/libutil/fparseln.c new file mode 100644 index 0000000..7d62cf7 --- /dev/null +++ b/lib/libutil/fparseln.c @@ -0,0 +1,233 @@ +/* $NetBSD: fparseln.c,v 1.9 1999/09/20 04:48:06 lukem Exp $ */ + +/* + * Copyright (c) 1997 Christos Zoulas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christos Zoulas. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <libutil.h> + +static int isescaped(const char *, const char *, int); + +/* isescaped(): + * Return true if the character in *p that belongs to a string + * that starts in *sp, is escaped by the escape character esc. + */ +static int +isescaped(sp, p, esc) + const char *sp, *p; + int esc; +{ + const char *cp; + size_t ne; + +#if 0 + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); +#endif + + /* No escape character */ + if (esc == '\0') + return 1; + + /* Count the number of escape characters that precede ours */ + for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++) + continue; + + /* Return true if odd number of escape characters */ + return (ne & 1) != 0; +} + + +/* fparseln(): + * Read a line from a file parsing continuations ending in \ + * and eliminating trailing newlines, or comments starting with + * the comment char. + */ +char * +fparseln(fp, size, lineno, str, flags) + FILE *fp; + size_t *size; + size_t *lineno; + const char str[3]; + int flags; +{ + static const char dstr[3] = { '\\', '\\', '#' }; + + size_t s, len; + char *buf; + char *ptr, *cp; + int cnt; + char esc, con, nl, com; + +#if 0 + _DIAGASSERT(fp != NULL); +#endif + + len = 0; + buf = NULL; + cnt = 1; + + if (str == NULL) + str = dstr; + + esc = str[0]; + con = str[1]; + com = str[2]; + /* + * XXX: it would be cool to be able to specify the newline character, + * but unfortunately, fgetln does not let us + */ + nl = '\n'; + + while (cnt) { + cnt = 0; + + if (lineno) + (*lineno)++; + + if ((ptr = fgetln(fp, &s)) == NULL) + break; + + if (s && com) { /* Check and eliminate comments */ + for (cp = ptr; cp < ptr + s; cp++) + if (*cp == com && !isescaped(ptr, cp, esc)) { + s = cp - ptr; + cnt = s == 0 && buf == NULL; + break; + } + } + + if (s && nl) { /* Check and eliminate newlines */ + cp = &ptr[s - 1]; + + if (*cp == nl) + s--; /* forget newline */ + } + + if (s && con) { /* Check and eliminate continuations */ + cp = &ptr[s - 1]; + + if (*cp == con && !isescaped(ptr, cp, esc)) { + s--; /* forget escape */ + cnt = 1; + } + } + + if (s == 0 && buf != NULL) + continue; + + if ((cp = realloc(buf, len + s + 1)) == NULL) { + free(buf); + return NULL; + } + buf = cp; + + (void) memcpy(buf + len, ptr, s); + len += s; + buf[len] = '\0'; + } + + if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL && + strchr(buf, esc) != NULL) { + ptr = cp = buf; + while (cp[0] != '\0') { + int skipesc; + + while (cp[0] != '\0' && cp[0] != esc) + *ptr++ = *cp++; + if (cp[0] == '\0' || cp[1] == '\0') + break; + + skipesc = 0; + if (cp[1] == com) + skipesc += (flags & FPARSELN_UNESCCOMM); + if (cp[1] == con) + skipesc += (flags & FPARSELN_UNESCCONT); + if (cp[1] == esc) + skipesc += (flags & FPARSELN_UNESCESC); + if (cp[1] != com && cp[1] != con && cp[1] != esc) + skipesc = (flags & FPARSELN_UNESCREST); + + if (skipesc) + cp++; + else + *ptr++ = *cp++; + *ptr++ = *cp++; + } + *ptr = '\0'; + len = strlen(buf); + } + + if (size) + *size = len; + return buf; +} + +#ifdef TEST + +int main(int, char **); + +int +main(argc, argv) + int argc; + char **argv; +{ + char *ptr; + size_t size, line; + + line = 0; + while ((ptr = fparseln(stdin, &size, &line, NULL, + FPARSELN_UNESCALL)) != NULL) + printf("line %d (%d) |%s|\n", line, size, ptr); + return 0; +} + +/* + +# This is a test +line 1 +line 2 \ +line 3 # Comment +line 4 \# Not comment \\\\ + +# And a comment \ +line 5 \\\ +line 6 + +*/ + +#endif /* TEST */ diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h new file mode 100644 index 0000000..e7067c4 --- /dev/null +++ b/lib/libutil/libutil.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1996 Peter Wemm <peter@FreeBSD.org>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _LIBUTIL_H_ +#define _LIBUTIL_H_ + +#include <sys/cdefs.h> + +#define PROPERTY_MAX_NAME 64 +#define PROPERTY_MAX_VALUE 512 + +/* for properties.c */ +typedef struct _property { + struct _property *next; + char *name; + char *value; +} *properties; + +/* Avoid pulling in all the include files for no need */ +struct termios; +struct winsize; +struct utmp; +struct in_addr; + +__BEGIN_DECLS +int extattr_namespace_to_string(int _attrnamespace, char **_string); +int extattr_string_to_namespace(const char *_string, int *_attrnamespace); +void login(struct utmp *_ut); +int login_tty(int _fd); +int logout(const char *_line); +void logwtmp(const char *_line, const char *_name, const char *_host); +void trimdomain(char *_fullhost, int _hostsize); +int openpty(int *_amaster, int *_aslave, char *_name, + struct termios *_termp, struct winsize *_winp); +int forkpty(int *_amaster, char *_name, + struct termios *_termp, struct winsize *_winp); +const char *uu_lockerr(int _uu_lockresult); +int uu_lock(const char *_ttyname); +int uu_unlock(const char *_ttyname); +int uu_lock_txfr(const char *_ttyname, pid_t _pid); +int _secure_path(const char *_path, uid_t _uid, gid_t _gid); +properties properties_read(int fd); +void properties_free(properties list); +char *property_find(properties list, const char *name); +char *auth_getval(const char *name); +int realhostname(char *host, size_t hsize, const struct in_addr *ip); +struct sockaddr; +int realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, + int addrlen); +#ifdef _STDIO_H_ /* avoid adding new includes */ +char *fparseln(FILE *, size_t *, size_t *, const char[3], int); +#endif +__END_DECLS + +#define UU_LOCK_INUSE (1) +#define UU_LOCK_OK (0) +#define UU_LOCK_OPEN_ERR (-1) +#define UU_LOCK_READ_ERR (-2) +#define UU_LOCK_CREAT_ERR (-3) +#define UU_LOCK_WRITE_ERR (-4) +#define UU_LOCK_LINK_ERR (-5) +#define UU_LOCK_TRY_ERR (-6) +#define UU_LOCK_OWNER_ERR (-7) + +/* return values from realhostname() */ +#define HOSTNAME_FOUND (0) +#define HOSTNAME_INCORRECTNAME (1) +#define HOSTNAME_INVALIDADDR (2) +#define HOSTNAME_INVALIDNAME (3) + +/* fparseln(3) */ +#define FPARSELN_UNESCESC 0x01 +#define FPARSELN_UNESCCONT 0x02 +#define FPARSELN_UNESCCOMM 0x04 +#define FPARSELN_UNESCREST 0x08 +#define FPARSELN_UNESCALL 0x0f + +#endif /* !_LIBUTIL_H_ */ diff --git a/lib/libutil/login.3 b/lib/libutil/login.3 new file mode 100644 index 0000000..dd595e9 --- /dev/null +++ b/lib/libutil/login.3 @@ -0,0 +1,65 @@ +.\" +.\" Copyright (c) 1996 Joerg Wunsch +.\" +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" " +.Dd December 29, 1996 +.Os +.Dt LOGIN 3 +.Sh NAME +.Nm login +.Nd "log a new login record to the utmp and wtmp files" +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In utmp.h +.In libutil.h +.Ft void +.Fn login "struct utmp *ut" +.Sh DESCRIPTION +The function +.Fn login +records the +.Ar ut +entry being passed into the appropriate slot of the +.Xr utmp 5 +file (according to the controlling terminal of the calling process), +and appends it to the +.Xr wtmp 5 +file. The calling process must have permission to write to both files. +.Sh RETURN VALUES +None. +.Sh SEE ALSO +.Xr logout 3 , +.Xr ttyslot 3 , +.Xr utmp 5 , +.Xr wtmp 5 +.Sh BUGS +The interface provided by +.Fn login +is rather crude. The caller must know about the details of a +.Va struct utmp . +Some better abstraction needs to be worked out. diff --git a/lib/libutil/login.c b/lib/libutil/login.c new file mode 100644 index 0000000..cbb6013 --- /dev/null +++ b/lib/libutil/login.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)login.c 8.1 (Berkeley) 6/4/93"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> + +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <utmp.h> +#include <libutil.h> + +void +login(ut) + struct utmp *ut; +{ + int fd; + int tty; + + tty = ttyslot(); + if (tty > 0 && (fd = open(_PATH_UTMP, O_WRONLY|O_CREAT, 0644)) >= 0) { + (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), L_SET); + (void)write(fd, ut, sizeof(struct utmp)); + (void)close(fd); + } + if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) { + (void)write(fd, ut, sizeof(struct utmp)); + (void)close(fd); + } +} diff --git a/lib/libutil/login.conf.5 b/lib/libutil/login.conf.5 new file mode 100644 index 0000000..4de6089 --- /dev/null +++ b/lib/libutil/login.conf.5 @@ -0,0 +1,386 @@ +.\" Copyright (c) 1996 David Nugent <davidn@blaze.net.au> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, is permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice immediately at the beginning of the file, without modification, +.\" this list of conditions, and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. This work was done expressly for inclusion into FreeBSD. Other use +.\" is permitted provided this notation is included. +.\" 4. Absolutely no warranty of function or purpose is made by the author +.\" David Nugent. +.\" 5. Modifications may be freely made to this file providing the above +.\" conditions are met. +.\" +.\" $FreeBSD$ +.\" +.Dd November 22, 1996 +.Dt LOGIN.CONF 5 +.Os +.Sh NAME +.Nm login.conf +.Nd login class capability database +.Sh SYNOPSIS +.Pa /etc/login.conf , +.Pa ~/.login_conf +.Sh DESCRIPTION +.Nm +contains various attributes and capabilities of login classes. +A login class (an optional annotation against each record in the user +account database, +.Pa /etc/master.passwd ) +determines session accounting, resource limits and user environment settings. +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. +.Pp +A special record "default" in the system user class capability database +.Pa /etc/login.conf +is used automatically for any +non-root user without a valid login class in +.Pa /etc/master.passwd . +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 +.Fx , +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". +If present, this file is used by +.Xr login 1 +to set user-defined environment settings which override those specified +in the system login capabilities database. +Only a subset of login capabilities may be overridden, typically those +which do not involve authentication, resource limits and accounting. +.Pp +Records in a class capabilities database consist of a number of +colon-separated fields. +The first entry for each record gives one or more names that a record is +to be known by, each separated by a '|' character. +The first name is the most common abbreviation. +The last name given should be a long name that is more descriptive +of the capability entry, and all others are synonyms. +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 +See +.Xr getcap 3 +for a more in-depth description of the format of a capability database. +.Sh CAPABILITIES +Fields within each record in the database follow the +.Xr getcap 3 +conventions for boolean, type string +.Ql \&= +and type numeric +.Ql \&# , +although type numeric is depreciated in favour of the string format and +either form is accepted for a numeric datum. +Values fall into the following categories: +.Bl -tag -width "program" +.It bool +If the name is present, then the boolean value is true; otherwise, it is +false +.It file +Path name to a data file +.It program +Path name to an executable file +.It list +A list of values (or pairs of values) separated by commas or spaces +.It path +A space or comma separated list of path names, following the usual csh +conventions (leading tilde with and without username being expanded to +home directories etc.) +.It number +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 +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. +.It size +A number which expresses a size. +The default interpretation of a value is the number of bytes, but a +suffix may specify alternate units: +.Bl -tag -offset indent -compact -width xxxx +.It b +explicitly selects 512-byte blocks +.It k +selects kilobytes (1024 bytes) +.It m +specifies a multiplier of 1 megabyte (1048576 bytes), +.It g +specifies units of gigabytes, and +.It t +represents terabytes. +.El +A size value is a numeric quantity and case of the suffix is not significant. +Concatenated values are added together. +.It time +A period of time, by default in seconds. +A prefix may specify a different unit: +.Bl -tag -offset indent -compact -width xxxx +.It y +indicates the number of 365 day years, +.It w +indicates the number of weeks, +.It d +the number of days, +.It h +the number of hours, +.It m +the number of minutes, and +.It s +the number of seconds. +.El +Concatenated values are added together. +For example, 2 hours and 40 minutes may be written either as +9600s, 160m or 2h40m. +.El +.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 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 "stacksize size Maximum stack size limit. +.El +.Pp +These resource limit entries actually specify both the maximum +and current limits (see +.Xr getrlimit 2 ) . +The current (soft) limit is the one normally used, although the user is +permitted to increase the current limit to the maximum (hard) limit. +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 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 "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 +values to which they are to be set. +.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 +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 +ensure octal interpretation. +.It "welcome file /etc/motd File containing welcome message. +.El +.Sh AUTHENTICATION +.Bl -column minpasswordlen indent indent +.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 +in the class may not access. +.It "login_prompt string The login prompt given by +.Xr login 1 +.It "minpasswordlen number 6 The minimum length a local password +may be. +.It "mixpasswordcase bool true Whether +.Xr passwd 1 +will warn the user if an all lower case password is entered. +.It "passwd_format string md5 The encryption format that new or +changed passwords will use. +Valid values include "des", "md5" and "blf". +NIS clients using a +.No non- Ns Fx +NIS server should probably use "des". +.It "passwd_prompt string The password prompt presented by +.Xr login 1 +.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 +disallowed. +.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 +in the class may not use for access. +.\".It "widepasswords bool false Use the wide password format. The wide password +.\" format allows up to 128 significant characters in the password. +.El +.Pp +These fields are intended to be used by +.Xr passwd 1 +and other programs in the login authentication system. +.Pp +Capabilities that set environment variables are scanned for both +.Ql \&~ +and +.Ql \&$ +characters, which are substituted for a user's home directory and name +respectively. +To pass these characters literally into the environment variable, escape +the character by preceding it with a backslash '\\'. +.Pp +The +.Em host.allow +and +.Em host.deny +entries are comma separated lists used for checking remote access to the system, +and consist of a list of hostnames and/or IP addresses against which remote +network logins are checked. +Items in these lists may contain wildcards in the form used by shell programs +for wildcard matching (See +.Xr fnmatch 3 +for details on the implementation). +The check on hosts is made against both the remote system's Internet address +and hostname (if available). +If both lists are empty or not specified, then logins from any remote host +are allowed. +If host.allow contains one or more hosts, then only remote systems matching +any of the items in that list are allowed to log in. +If host.deny contains one or more hosts, then a login from any matching hosts +will be disallowed. +.Pp +The +.Em times.allow +and +.Em times.deny +entries consist of a comma-separated list of time periods during which the users +in a class are allowed to be logged in. +These are expressed as one or more day codes followed by a start and end times +expressed in 24 hour format, separated by a hyphen or dash. +For example, MoThSa0200-1300 translates to Monday, Thursday and Saturday between +the hours of 2 am and 1 p.m.. +If both of these time lists are empty, users in the class are allowed access at +any time. +If +.Em times.allow +is specified, then logins are only allowed during the periods given. +If +.Em times.deny +is specified, then logins are denied during the periods given, regardless of whether +one of the periods specified in +.Em times.allow +applies. +.Pp +Note that +.Xr login 1 +enforces only that the actual login falls within periods allowed by these entries. +Further enforcement over the life of a session requires a separate daemon to +monitor transitions from an allowed period to a non-allowed one. +.Pp +The +.Em ttys.allow +and +.Em ttys.deny +entries contain a comma-separated list of tty devices (without the /dev/ prefix) +that a user in a class may use to access the system, and/or a list of ttygroups +(See +.Xr getttyent 3 +and +.Xr ttys 5 +for information on ttygroups). +If neither entry exists, then the choice of login device used by the user is +unrestricted. +If only +.Em ttys.allow +is specified, then the user is restricted only to ttys in the given +group or device list. +If only +.Em ttys.deny +is specified, then the user is prevented from using the specified devices or +devices in the group. +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 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 +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 +login sessions will be accounted. +.It "host.exempt list List of remote host wildcards from which +login session accounting is exempted. +.It "idletime time Maximum idle time before logout. +.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 +login sessions on ttys in any group. +.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 +is exempt. +.It "warnexpire time Advance notice for pending account expiry. +.It "warnpassword time Advance notice for pending password expiry. +.It "warntime time Advance notice for pending out-of-time. +.It "weektime time Maximum login time per week. +.El +.Pp +These fields are used by the time accounting system, which regulates, +controls and records user login access. +.Pp +The +.Em ttys.accounted +and +.Em ttys.exempt +fields operate in a similar manner to +.Em ttys.allow +and +.Em ttys.deny +as explained +above. +Similarly with the +.Em host.accounted +and +.Em host.exempt +lists. +.Sh SEE ALSO +.Xr cap_mkdb 1 , +.Xr login 1 , +.Xr getcap 3 , +.Xr getttyent 3 , +.Xr login_cap 3 , +.Xr login_class 3 , +.Xr passwd 5 , +.Xr ttys 5 diff --git a/lib/libutil/login_auth.3 b/lib/libutil/login_auth.3 new file mode 100644 index 0000000..3750bd6 --- /dev/null +++ b/lib/libutil/login_auth.3 @@ -0,0 +1,72 @@ +.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, is permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice immediately at the beginning of the file, without modification, +.\" this list of conditions, and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. This work was done expressly for inclusion into FreeBSD. Other use +.\" is permitted provided this notation is included. +.\" 4. Absolutely no warranty of function or purpose is made by the author +.\" David Nugent. +.\" 5. Modifications may be freely made to this file providing the above +.\" conditions are met. +.\" +.\" $FreeBSD$ +.\" +.Dd December 29, 1996 +.Os +.Dt LOGIN_AUTH 3 +.Sh NAME +.\" .Nm authenticate +.\" .Nm auth_script +.\" .Nm auth_env +.\" .Nm auth_scan +.\" .Nm auth_rmfiles +.Nm auth_checknologin , +.Nm auth_cat +.\" .Nm auth_ttyok +.\" .Nm auth_hostok +.\" .Nm auth_timesok +.Nd "authentication style support library for login class capabilities database" +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In login_cap.h +.\" .Ft int +.\". Fn authenticate "const char *name" "const char *classname" "const char *style" "const char *service" +.\" .Ft int +.\" .Fn auth_script "const char * path" ... +.\" .Ft void +.\" .Fn auth_env "void" +.\" .Ft int +.\" .Fn auth_scan "int ok" +.\" .Ft void +.\" .Fn auth_rmfiles "void" +.Ft void +.Fn auth_checknologin "login_cap_t *lc" +.Ft int +.Fn auth_cat "const char *file" +.\" .Ft int +.\" .Fn auth_ttyok "login_cap_t *lc" "const char *tty" +.\" .Ft int +.\" .Fn auth_hostok "login_cap_t *lc" "const char *hostname" "char const *ip" +.\" .Ft int +.\" .Fn auth_timesok "login_cap_t *lc" "time_t now" +.Sh DESCRIPTION +This set of functions support the login class authorisation style interface provided +by +.Xr login.conf 5 . +.\" .Sh RETURN VALUES +.Sh SEE ALSO +.Xr getcap 3 , +.Xr login_cap 3 , +.Xr login_class 3 , +.Xr login.conf 5 , +.Xr termcap 5 diff --git a/lib/libutil/login_auth.c b/lib/libutil/login_auth.c new file mode 100644 index 0000000..70227a9 --- /dev/null +++ b/lib/libutil/login_auth.c @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 1996 by + * Sean Eric Fagan <sef@kithrup.com> + * David Nugent <davidn@blaze.net.au> + * All rights reserved. + * + * Portions copyright (c) 1995,1997 by + * Berkeley Software Design, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. This work was done expressly for inclusion into FreeBSD. Other use + * is permitted provided this notation is included. + * 4. Absolutely no warranty of function or purpose is made by the authors. + * 5. Modifications may be freely made to this file providing the above + * conditions are met. + * + * Low-level routines relating to the user capabilities database + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <ctype.h> +#include <pwd.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <login_cap.h> +#include <stdarg.h> +#include <paths.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <err.h> +#include <libutil.h> + + +/* + * auth_checknologin() + * Checks for the existance of a nologin file in the login_cap + * capability <lc>. If there isn't one specified, then it checks + * to see if this class should just ignore nologin files. Lastly, + * it tries to print out the default nologin file, and, if such + * exists, it exits. + */ + +void +auth_checknologin(login_cap_t *lc) +{ + char *file; + + /* Do we ignore a nologin file? */ + if (login_getcapbool(lc, "ignorenologin", 0)) + return; + + /* Note that <file> will be "" if there is no nologin capability */ + if ((file = login_getcapstr(lc, "nologin", "", NULL)) == NULL) + exit(1); + + /* + * *file is true IFF there was a "nologin" capability + * Note that auth_cat() returns 1 only if the specified + * file exists, and is readable. E.g., /.nologin exists. + */ + if ((*file && auth_cat(file)) || auth_cat(_PATH_NOLOGIN)) + exit(1); +} + + +/* + * auth_cat() + * Checks for the readability of <file>; if it can be opened for + * reading, it prints it out to stdout, and then exits. Otherwise, + * it returns 0 (meaning no nologin file). + */ + +int +auth_cat(const char *file) +{ + int fd, count; + char buf[BUFSIZ]; + + if ((fd = open(file, O_RDONLY)) < 0) + return 0; + while ((count = read(fd, buf, sizeof(buf))) > 0) + (void)write(fileno(stdout), buf, count); + close(fd); + sleep(5); /* wait an arbitrary time to drain */ + return 1; +} diff --git a/lib/libutil/login_cap.3 b/lib/libutil/login_cap.3 new file mode 100644 index 0000000..d05426c --- /dev/null +++ b/lib/libutil/login_cap.3 @@ -0,0 +1,421 @@ +.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, is permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice immediately at the beginning of the file, without modification, +.\" this list of conditions, and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. This work was done expressly for inclusion into FreeBSD. Other use +.\" is permitted provided this notation is included. +.\" 4. Absolutely no warranty of function or purpose is made by the author +.\" David Nugent. +.\" 5. Modifications may be freely made to this file providing the above +.\" conditions are met. +.\" +.\" $FreeBSD$ +.\" +.Dd December 27, 1996 +.Os +.Dt LOGIN_CAP 3 +.Sh NAME +.Nm login_close , +.Nm login_getcapbool , +.Nm login_getcaplist , +.Nm login_getcapnum , +.Nm login_getcapstr , +.Nm login_getcapsize , +.Nm login_getcaptime , +.Nm login_getclass , +.Nm login_getclassbyname , +.Nm login_getpwclass , +.Nm login_getstyle , +.Nm login_getuserclass , +.Nm login_setcryptfmt +.Nd "functions for accessing the login class capabilities database" +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In login_cap.h +.Ft void +.Fn login_close "login_cap_t *lc" +.Ft login_cap_t * +.Fn login_getclassbyname "const char *nam" "const struct passwd *pwd" +.Ft login_cap_t * +.Fn login_getclass "const char *nam" +.Ft login_cap_t * +.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 ** +.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 rlim_t +.Fn login_getcaptime "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error" +.Ft rlim_t +.Fn login_getcapnum "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error" +.Ft rlim_t +.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_setcryptfmt "login_cap_t *lc" "const char *def" "const char *error" +.Sh DESCRIPTION +These functions represent a programming interface to the login +classes database provided in +.Xr login.conf 5 . +This database contains capabilities, attributes and default environment +and accounting settings for users and programs running as specific users, +as determined by the login class field within entries in +.Pa /etc/master.passwd . +.Pp +Entries in +.Xr login.conf 5 +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'. +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. +This is similar to the format used in +.Xr termcap 5 , +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=<recordid>. +The result is that the entire record referenced by <recordid> replaces +the 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. +.Pp +The +.Nm login_cap +interface provides a convenient means of retrieving login class +records with all tc= references expanded. +A program will typically call one of +.Fn login_getclass , +.Fn login_getpwclass , +.Fn login_getuserclass +or +.Fn login_getclassbyname +according to its requirements. +Each of these functions returns a login capabilities structure, +.Ft 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 +.Fn login_close +function should be called to free all resources used. +.Pp +The structure of login_cap_t is defined in login_cap.h, as: +.Bd -literal -offset indent +typedef struct { + char *lc_class; + char *lc_cap; + char *lc_style; +} login_cap_t; +.Ed +.Pp +The +.Ar 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 +.Fn login_getpwclass , +by class name using +.Fn login_getclass , +or +.Fn login_getuserclass . +If the referenced user has no login class specified in +.Pa /etc/master.passwd , +the class name is 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", +with that name returned in the +.Ar lc_class +field. +In addition, if the referenced user has a UID of 0 (normally, +"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". +.Pp +The +.Ar 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 +.Fn getcap +style functions to access the record directly. +.Pp +The +.Ar 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 get*class +functions return a login_cap_t object which is used to access +the matching or default record in the capabilities database. +.Fn 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 +.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. +.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 +memory allocation error or for some reason +.Xr cgetent 3 +is unable to access the login capabilities database, this function +returns NULL. +.Pp +The functions +.Fn login_getpwclass , +.Fn login_getclass +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. +The difference between these functions is that +.Fn login_getuserclass +includes the user's overriding +.Pa .login_conf +that exists in the user's home directory, and +.Fn login_getpwclass +and +.Fn login_getclass +restrict lookup only to the system login class database in +.Pa /etc/login.conf . +As explained earlier, +.Fn login_getpwclass +only differs from +.Fn login_getclass +in that it allows the default class for user 'root' as "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. +.Pp +Once a program no longer wishes to use a login_cap_t object, +.Fn login_close +may be called to free all resources used by the login class. +.Fn login_close +may be passed a 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, +a capability tag as the second, and remaining parameters being +default and error values that are returned if the capability is +not found. +The type of the additional parameters passed and returned depend +on the +.Em type +of capability each deals with, be it a simple string, a list, +a time value, a file or memory size value, a path (consisting of +a colon-separated list of directories) or a boolean flag. +The manpage for +.Xr login.conf 5 +deals in specific tags and their type. +.Pp +Note that with all functions in this group, you should not call +.Xr free 3 +on any pointers returned. +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 "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 +is returned as the default value, or if an error +occurs, the value in the +.Ar 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. +Within the login class database, some tags are of type +.Em list , +which consist of one or more comma- or space separated +values. +Usually, this function is not called directly from an +application, but is used indirectly via +.Fn login_getstyle . +.It Fn login_getpath +This function returns a list of directories separated by colons +.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 +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. +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 +.Fx ) , +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. +.It Fn login_getcapnum +This function returns a numeric value for a tag, expressed either as +tag=<value> or the standard +.Fn cgetnum +format tag#<value>. +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 the given capability tag cannot be found, the +.Ar def +parameter is returned, and if an error occurs, the +.Ar 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 +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 +terrabytes. +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 +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 +.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 +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-<auth>" in the capability record. +If not present, then look for the default tag "auth=". +.It +If no valid authorisation list was found from the previous step, then +default to "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" +authorisation. +.It +If 'style' is found in the chosen list of authorisation methods, then +return that, otherwise return NULL. +.El +.Pp +This scheme allows the administrator to determine the types of +authorisation methods accepted by the system, depending on the +means by which the access occurs. +For example, the administrator may require skey or kerberos as +the authentication method used for access to the system via the +network, and standard methods via direct dialup or console +logins, significantly reducing the risk of password discovery +by "snooping" network packets. +.It Fn login_setcryptfmt +The +.Fn login_setcryptfmt +function is used to set the +.Xr crypt 3 +format using the +.Ql passwd_format +configuration entry. +If no entry is found, +.Fa def +is taken to be used as the fallback. +If calling +.Xr crypt_set_format 3 +on the specifier fails, +.Fa error +is returned to indicate this. +.El +.Sh SEE ALSO +.Xr crypt 3 , +.Xr getcap 3 , +.Xr login_class 3 , +.Xr login.conf 5 , +.Xr termcap 5 diff --git a/lib/libutil/login_cap.c b/lib/libutil/login_cap.c new file mode 100644 index 0000000..9797c8b --- /dev/null +++ b/lib/libutil/login_cap.c @@ -0,0 +1,807 @@ +/*- + * Copyright (c) 1996 by + * Sean Eric Fagan <sef@kithrup.com> + * David Nugent <davidn@blaze.net.au> + * All rights reserved. + * + * Portions copyright (c) 1995,1997 + * Berkeley Software Design, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. This work was done expressly for inclusion into FreeBSD. Other use + * is permitted provided this notation is included. + * 4. Absolutely no warranty of function or purpose is made by the authors. + * 5. Modifications may be freely made to this file providing the above + * conditions are met. + * + * Low-level routines relating to the user capabilities database + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/param.h> +#include <pwd.h> +#include <libutil.h> +#include <syslog.h> +#include <login_cap.h> + +/* + * allocstr() + * Manage a single static pointer for handling a local char* buffer, + * resizing as necessary to contain the string. + * + * allocarray() + * Manage a static array for handling a group of strings, resizing + * when necessary. + */ + +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 char * +allocstr(char *str) +{ + char *p; + + size_t sz = strlen(str) + 1; /* realloc() only if necessary */ + if (sz <= internal_stringsz) + p = strcpy(internal_string, str); + else if ((p = realloc(internal_string, sz)) != NULL) { + internal_stringsz = sz; + internal_string = strcpy(p, str); + } + return p; +} + + +static char ** +allocarray(size_t sz) +{ + char **p; + + if (sz <= internal_arraysz) + p = internal_array; + else if ((p = realloc(internal_array, sz * sizeof(char*))) != NULL) { + internal_arraysz = sz; + internal_array = p; + } + return p; +} + + +/* + * arrayize() + * Turn a simple string <str> separated by any of + * the set of <chars> into an array. The last element + * of the array will be NULL, as is proper. + * Free using freearraystr() + */ + +static char ** +arrayize(char *str, const char *chars, int *size) +{ + int i; + char *ptr; + char **res = NULL; + + /* count the sub-strings */ + for (i = 0, ptr = str; *ptr; i++) { + int count = strcspn(ptr, chars); + ptr += count; + if (*ptr) + ++ptr; + } + + /* alloc the array */ + if ((ptr = allocstr(str)) != NULL) { + if ((res = allocarray(++i)) == NULL) + free(str); + else { + /* now split the string */ + i = 0; + while (*ptr) { + int count = strcspn(ptr, chars); + res[i++] = ptr; + ptr += count; + if (*ptr) + *ptr++ = '\0'; + } + res[i] = NULL; + } + } + + if (size) + *size = i; + + return res; +} + + +/* + * login_close() + * Frees up all resources relating to a login class + * + */ + +void +login_close(login_cap_t * lc) +{ + if (lc) { + free(lc->lc_style); + free(lc->lc_class); + free(lc->lc_cap); + free(lc); + if (--lc_object_count == 0) { + free(internal_string); + free(internal_array); + internal_array = NULL; + internal_arraysz = 0; + internal_string = NULL; + internal_stringsz = 0; + cgetclose(); + } + } +} + + +/* + * 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. + * Return a filled-out login_cap_t structure, including + * class name, and the capability record buffer. + */ + +login_cap_t * +login_getclassbyname(char const *name, const struct passwd *pwd) +{ + login_cap_t *lc; + + if ((lc = malloc(sizeof(login_cap_t))) != NULL) { + int r, me, i = 0; + uid_t euid = 0; + gid_t egid = 0; + const char *msg = NULL; + const char *dir; + char userpath[MAXPATHLEN]; + + static char *login_dbarray[] = { NULL, NULL, NULL }; + + me = (name != NULL && strcmp(name, LOGIN_MECLASS) == 0); + dir = (!me || pwd == NULL) ? NULL : pwd->pw_dir; + /* + * Switch to user mode before checking/reading its ~/.login_conf + * - some NFSes have root read access disabled. + * + * XXX: This fails to configure additional groups. + */ + if (dir) { + euid = geteuid(); + egid = getegid(); + (void)setegid(pwd->pw_gid); + (void)seteuid(pwd->pw_uid); + } + + 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 */ + } + 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)); + lc->lc_cap = lc->lc_class = lc->lc_style = NULL; + + if (name == NULL || *name == '\0') + name = LOGIN_DEFCLASS; + + switch (cgetent(&lc->lc_cap, login_dbarray, (char*)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) + close(r); + /* + * If there's at least one login class database, + * and we aren't searching for a default class + * then complain about a non-existent class. + */ + if (r >= 0 || strcmp(name, LOGIN_DEFCLASS) != 0) + syslog(LOG_ERR, "login_getclass: unknown class '%s'", name); + /* 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) + break; + /* Fallthru - just return system defaults */ + case 0: /* success! */ + if ((lc->lc_class = strdup(name)) != NULL) { + if (dir) { + (void)seteuid(euid); + (void)setegid(egid); + } + ++lc_object_count; + return lc; + } + msg = "%s: strdup: %m"; + break; + case -2: + msg = "%s: retrieving class information: %m"; + break; + case -3: + msg = "%s: 'tc=' reference loop '%s'"; + break; + case 1: + msg = "couldn't resolve 'tc=' reference in '%s'"; + break; + default: + msg = "%s: unexpected cgetent() error '%s': %m"; + break; + } + if (dir) { + (void)seteuid(euid); + (void)setegid(egid); + } + if (msg != NULL) + syslog(LOG_ERR, msg, "login_getclass", name); + free(lc); + } + + return NULL; +} + + + +/* + * login_getclass() + * Get the login class for the system (only) login class database. + * Return a filled-out login_cap_t structure, including + * class name, and the capability record buffer. + */ + +login_cap_t * +login_getclass(const char *cls) +{ + return login_getclassbyname(cls, NULL); +} + + +/* + * login_getclass() + * 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"). + * Return a filled-out login_cap_t structure, including + * class name, and the capability record buffer. + */ + +login_cap_t * +login_getpwclass(const struct passwd *pwd) +{ + const char *cls = NULL; + + if (pwd != NULL) { + cls = pwd->pw_class; + if (cls == NULL || *cls == '\0') + cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; + } + return login_getclassbyname(cls, pwd); +} + + +/* + * login_getuserclass() + * Get the login class for a given password entry, allowing user + * overrides via ~/.login_conf. + */ + +login_cap_t * +login_getuserclass(const struct passwd *pwd) +{ + return login_getclassbyname(LOGIN_MECLASS, 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 + * an error string on error. + */ + +char * +login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error) +{ + char *res; + int ret; + + if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0') + return def; + + if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) + return def; + return (ret >= 0) ? res : error; +} + + +/* + * login_getcaplist() + * Given a login_cap entry, and a capability name, return the + * value defined for that capability split into an array of + * strings. + */ + +char ** +login_getcaplist(login_cap_t *lc, const char *cap, const char *chars) +{ + char *lstring; + + if (chars == NULL) + chars = ", \t"; + if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL) + return arrayize(lstring, chars, NULL); + return NULL; +} + + +/* + * login_getpath() + * From the login_cap_t <lc>, get the capability <cap> which is + * formatted as either a space or comma delimited list of paths + * and append them all into a string and separate by semicolons. + * If there is an error of any kind, return <error>. + */ + +char * +login_getpath(login_cap_t *lc, const char *cap, char * error) +{ + char *str; + + if ((str = login_getcapstr(lc, (char*)cap, NULL, NULL)) == NULL) + str = error; + else { + char *ptr = str; + + while (*ptr) { + int count = strcspn(ptr, ", \t"); + ptr += count; + if (*ptr) + *ptr++ = ':'; + } + } + return str; +} + + +static int +isinfinite(const char *s) +{ + static const char *infs[] = { + "infinity", + "inf", + "unlimited", + "unlimit", + "-1", + NULL + }; + const char **i = &infs[0]; + + while (*i != NULL) { + if (strcasecmp(s, *i) == 0) + return 1; + ++i; + } + return 0; +} + + +static u_quad_t +rmultiply(u_quad_t n1, u_quad_t n2) +{ + u_quad_t m, r; + int b1, b2; + + static int bpw = 0; + + /* Handle simple cases */ + if (n1 == 0 || n2 == 0) + return 0; + if (n1 == 1) + return n2; + if (n2 == 1) + return n1; + + /* + * sizeof() returns number of bytes needed for storage. + * This may be different from the actual number of useful bits. + */ + if (!bpw) { + bpw = sizeof(u_quad_t) * 8; + while (((u_quad_t)1 << (bpw-1)) == 0) + --bpw; + } + + /* + * First check the magnitude of each number. If the sum of the + * magnatude is way to high, reject the number. (If this test + * is not done then the first multiply below may overflow.) + */ + for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1) + ; + for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2) + ; + if (b1 + b2 - 2 > bpw) { + errno = ERANGE; + return (UQUAD_MAX); + } + + /* + * Decompose the multiplication to be: + * h1 = n1 & ~1 + * h2 = n2 & ~1 + * l1 = n1 & 1 + * l2 = n2 & 1 + * (h1 + l1) * (h2 + l2) + * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2) + * + * Since h1 && h2 do not have the low bit set, we can then say: + * + * (h1>>1 * h2>>1 * 4) + ... + * + * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will + * overflow. + * + * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2) + * then adding in residual amout will cause an overflow. + */ + + m = (n1 >> 1) * (n2 >> 1); + if (m >= ((u_quad_t)1 << (bpw-2))) { + errno = ERANGE; + return (UQUAD_MAX); + } + m *= 4; + + r = (n1 & n2 & 1) + + (n2 & 1) * (n1 & ~(u_quad_t)1) + + (n1 & 1) * (n2 & ~(u_quad_t)1); + + if ((u_quad_t)(m + r) < m) { + errno = ERANGE; + return (UQUAD_MAX); + } + m += r; + + return (m); +} + + +/* + * login_getcaptime() + * From the login_cap_t <lc>, get the capability <cap>, which is + * formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not + * present in <lc>, return <def>; if there is an error of some kind, + * return <error>. + */ + +rlim_t +login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) +{ + char *res, *ep, *oval; + int r; + rlim_t tot; + + errno = 0; + if (lc == NULL || lc->lc_cap == NULL) + return def; + + /* + * Look for <cap> in lc_cap. + * If it's not there (-1), return <def>. + * If there's an error, return <error>. + */ + + if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) + return def; + else if (r < 0) { + errno = ERANGE; + return error; + } + + /* "inf" and "infinity" are special cases */ + if (isinfinite(res)) + return RLIM_INFINITY; + + /* + * Now go through the string, turning something like 1h2m3s into + * an integral value. Whee. + */ + + errno = 0; + tot = 0; + oval = res; + while (*res) { + rlim_t tim = strtoq(res, &ep, 0); + rlim_t mult = 1; + + if (ep == NULL || ep == res || errno != 0) { + invalid: + syslog(LOG_WARNING, "login_getcaptime: class '%s' bad value %s=%s", + lc->lc_class, cap, oval); + errno = ERANGE; + return error; + } + /* Look for suffixes */ + switch (*ep++) { + case 0: + ep--; + break; /* end of string */ + case 's': case 'S': /* seconds */ + break; + case 'm': case 'M': /* minutes */ + mult = 60; + break; + case 'h': case 'H': /* hours */ + mult = 60L * 60L; + break; + case 'd': case 'D': /* days */ + mult = 60L * 60L * 24L; + break; + case 'w': case 'W': /* weeks */ + mult = 60L * 60L * 24L * 7L; + break; + case 'y': case 'Y': /* 365-day years */ + mult = 60L * 60L * 24L * 365L; + break; + default: + goto invalid; + } + res = ep; + tot += rmultiply(tim, mult); + if (errno) + goto invalid; + } + + return tot; +} + + +/* + * login_getcapnum() + * From the login_cap_t <lc>, extract the numerical value <cap>. + * If it is not present, return <def> for a default, and return + * <error> if there is an error. + * Like login_getcaptime(), only it only converts to a number, not + * to a time; "infinity" and "inf" are 'special.' + */ + +rlim_t +login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) +{ + char *ep, *res; + int r; + rlim_t val; + + if (lc == NULL || lc->lc_cap == NULL) + return def; + + /* + * For BSDI compatibility, try for the tag=<val> first + */ + if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) { + long lval; + /* string capability not present, so try for tag#<val> as numeric */ + if ((r = cgetnum(lc->lc_cap, (char *)cap, &lval)) == -1) + return def; /* Not there, so return default */ + else if (r >= 0) + return (rlim_t)lval; + } + + if (r < 0) { + errno = ERANGE; + return error; + } + + if (isinfinite(res)) + return RLIM_INFINITY; + + errno = 0; + val = strtoq(res, &ep, 0); + if (ep == NULL || ep == res || errno != 0) { + syslog(LOG_WARNING, "login_getcapnum: class '%s' bad value %s=%s", + lc->lc_class, cap, res); + errno = ERANGE; + return error; + } + + return val; +} + + + +/* + * login_getcapsize() + * From the login_cap_t <lc>, extract the capability <cap>, which is + * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity". + * If not present, return <def>, or <error> if there is an error of + * some sort. + */ + +rlim_t +login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) +{ + char *ep, *res, *oval; + int r; + rlim_t tot; + + if (lc == NULL || lc->lc_cap == NULL) + return def; + + if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) + return def; + else if (r < 0) { + errno = ERANGE; + return error; + } + + if (isinfinite(res)) + return RLIM_INFINITY; + + errno = 0; + tot = 0; + oval = res; + while (*res) { + rlim_t siz = strtoq(res, &ep, 0); + rlim_t mult = 1; + + if (ep == NULL || ep == res || errno != 0) { + invalid: + syslog(LOG_WARNING, "login_getcapsize: class '%s' bad value %s=%s", + lc->lc_class, cap, oval); + errno = ERANGE; + return error; + } + switch (*ep++) { + case 0: /* end of string */ + ep--; + break; + case 'b': case 'B': /* 512-byte blocks */ + mult = 512; + break; + case 'k': case 'K': /* 1024-byte Kilobytes */ + mult = 1024; + break; + case 'm': case 'M': /* 1024-k kbytes */ + mult = 1024 * 1024; + break; + case 'g': case 'G': /* 1Gbyte */ + mult = 1024 * 1024 * 1024; + break; + case 't': case 'T': /* 1TBte */ + mult = 1024LL * 1024LL * 1024LL * 1024LL; + break; + default: + goto invalid; + } + res = ep; + tot += rmultiply(siz, mult); + if (errno) + goto invalid; + } + + return tot; +} + + +/* + * login_getcapbool() + * From the login_cap_t <lc>, check for the existance of the capability + * of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return + * the whether or not <cap> exists there. + */ + +int +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); +} + + +/* + * login_getstyle() + * Given a login_cap entry <lc>, and optionally a type of auth <auth>, + * and optionally a style <style>, find the style that best suits these + * rules: + * 1. If <auth> is non-null, look for an "auth-<auth>=" string + * in the capability; if not present, default to "auth=". + * 2. If there is no auth list found from (1), default to + * "passwd" as an authorization list. + * 3. If <style> is non-null, look for <style> in the list of + * authorization methods found from (2); if <style> is NULL, default + * to LOGIN_DEFSTYLE ("passwd"). + * 4. If the chosen style is found in the chosen list of authorization + * methods, return that; otherwise, return NULL. + * E.g.: + * login_getstyle(lc, NULL, "ftp"); + * login_getstyle(lc, "login", NULL); + * login_getstyle(lc, "skey", "network"); + */ + +char * +login_getstyle(login_cap_t *lc, char *style, const char *auth) +{ + int i; + char **authtypes = NULL; + char *auths= NULL; + char realauth[64]; + + static char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL }; + + if (auth != NULL && *auth != '\0') { + if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < sizeof realauth) + authtypes = login_getcaplist(lc, realauth, NULL); + } + + if (authtypes == NULL) + authtypes = login_getcaplist(lc, "auth", NULL); + + if (authtypes == NULL) + authtypes = defauthtypes; + + /* + * We have at least one authtype now; auths is a comma-separated + * (or space-separated) list of authentication types. We have to + * convert from this to an array of char*'s; authtypes then gets this. + */ + i = 0; + if (style != NULL && *style != '\0') { + while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0) + i++; + } + + lc->lc_style = NULL; + if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL) + lc->lc_style = auths; + + if (lc->lc_style != NULL) + lc->lc_style = strdup(lc->lc_style); + + return lc->lc_style; +} diff --git a/lib/libutil/login_cap.h b/lib/libutil/login_cap.h new file mode 100644 index 0000000..81983da --- /dev/null +++ b/lib/libutil/login_cap.h @@ -0,0 +1,157 @@ +/*- + * Copyright (c) 1996 by + * Sean Eric Fagan <sef@kithrup.com> + * David Nugent <davidn@blaze.net.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. This work was done expressly for inclusion into FreeBSD. Other use + * is permitted provided this notation is included. + * 4. Absolutely no warranty of function or purpose is made by the authors. + * 5. Modifications may be freely made to this file providing the above + * conditions are met. + * + * 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$ + */ + +#ifndef _LOGIN_CAP_H_ +#define _LOGIN_CAP_H_ + +#define LOGIN_DEFCLASS "default" +#define LOGIN_DEFROOTCLASS "root" +#define LOGIN_MECLASS "me" +#define LOGIN_DEFSTYLE "passwd" +#define LOGIN_DEFSERVICE "login" +#define LOGIN_DEFUMASK 022 +#define LOGIN_DEFPRI 0 +#define _PATH_LOGIN_CONF "/etc/login.conf" +#define _FILE_LOGIN_CONF ".login_conf" +#define _PATH_AUTHPROG "/usr/libexec/login_" + +#define LOGIN_SETGROUP 0x0001 /* set group */ +#define LOGIN_SETLOGIN 0x0002 /* set login (via setlogin) */ +#define LOGIN_SETPATH 0x0004 /* set path */ +#define LOGIN_SETPRIORITY 0x0008 /* set priority */ +#define LOGIN_SETRESOURCES 0x0010 /* set resources (cputime, etc.) */ +#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 BI_AUTH "authorize" /* accepted authentication */ +#define BI_REJECT "reject" /* rejected authentication */ +#define BI_CHALLENG "reject challenge" /* reject with a challenge */ +#define BI_SILENT "reject silent" /* reject silently */ +#define BI_REMOVE "remove" /* remove file on error */ +#define BI_ROOTOKAY "authorize root" /* root authenticated */ +#define BI_SECURE "authorize secure" /* okay on non-secure line */ +#define BI_SETENV "setenv" /* set environment variable */ +#define BI_VALUE "value" /* set local variable */ + +#define AUTH_OKAY 0x01 /* user authenticated */ +#define AUTH_ROOTOKAY 0x02 /* root login okay */ +#define AUTH_SECURE 0x04 /* secure login */ +#define AUTH_SILENT 0x08 /* silent rejection */ +#define AUTH_CHALLENGE 0x10 /* a chellenge was given */ + +#define AUTH_ALLOW (AUTH_OKAY | AUTH_ROOTOKAY | AUTH_SECURE) + +typedef struct login_cap { + char *lc_class; + char *lc_cap; + char *lc_style; +} login_cap_t; + +typedef struct login_time { + u_short lt_start; /* Start time */ + u_short lt_end; /* End time */ +#define LTM_NONE 0x00 +#define LTM_SUN 0x01 +#define LTM_MON 0x02 +#define LTM_TUE 0x04 +#define LTM_WED 0x08 +#define LTM_THU 0x10 +#define LTM_FRI 0x20 +#define LTM_SAT 0x40 +#define LTM_ANY 0x7F +#define LTM_WK 0x3E +#define LTM_WD 0x41 + u_char lt_dow; /* Days of week */ +} login_time_t; + +#define LC_MAXTIMES 64 + +#include <sys/cdefs.h> +__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 *); +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); + +struct tm; + +login_time_t parse_lt(const char *); +int in_ltm(const login_time_t *, struct tm *, time_t *); +int in_ltms(const login_time_t *, struct tm *, 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 *); + +__END_DECLS + +#endif /* _LOGIN_CAP_H_ */ diff --git a/lib/libutil/login_class.3 b/lib/libutil/login_class.3 new file mode 100644 index 0000000..4ad9dc7 --- /dev/null +++ b/lib/libutil/login_class.3 @@ -0,0 +1,189 @@ +.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, is permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice immediately at the beginning of the file, without modification, +.\" this list of conditions, and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. This work was done expressly for inclusion into FreeBSD. Other use +.\" is permitted provided this notation is included. +.\" 4. Absolutely no warranty of function or purpose is made by the author +.\" David Nugent. +.\" 5. Modifications may be freely made to this file providing the above +.\" conditions are met. +.\" +.\" $FreeBSD$ +.\" +.Dd December 28, 1996 +.Os +.Dt LOGIN_CLASS 3 +.Sh NAME +.Nm setclasscontext , +.Nm setclassenvironment , +.Nm setclassresources , +.Nm setusercontext +.Nd "functions for using the login class capabilities database" +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In login_cap.h +.Ft int +.Fn setclasscontext "const char *classname" "unsigned int flags" +.Ft int +.Fn setusercontext "login_cap_t *lc" "const struct passwd *pwd" "uid_t uid" "unsigned int flags" +.Ft void +.Fn setclassresources "login_cap_t *lc" +.Ft void +.Fn setclassenvironment "login_cap_t *lc" "const struct passwd *pwd" "int paths" +.Sh DESCRIPTION +These functions provide a higher level interface to the login class +database than those documented in +.Xr login_cap 3 . +These functions are used to set resource limits, environment and +accounting settings for users on logging into the system and when +selecting an appropriate set of environment and resource settings +for system daemons based on login classes. +These functions may only be called if the current process is +running with root privileges. +If the LOGIN_SETLOGIN flag is used this function calls +.Xr setlogin 2 , +and due care must be taken as detailed in the manpage for that +function and this affects all processes running in the same session +and not just the current process. +.Pp +.Fn setclasscontext +sets various class context values (resource limits, umask and +process priorities) based on values for a specific named class. +.Pp +The function +.Fn setusercontext +sets class context values based on a given login_cap_t +object, a specific passwd record (if login_cap_t is NULL), +sets the current session's login and the current process +user and group ownership. +Each of these functions is selectable via bit-flags passed +in the +.Ar flags +parameter, which is comprised of one or more of the following: +.Bl -tag -width LOGIN_SETRESOURCES +.It LOGIN_SETLOGIN +Set the login associated with the current session to the user +specified in the passwd structure. +.Xr setlogin 2 . +The +.Ar pwd +parameter must not be NULL if this option is used. +.It LOGIN_SETUSER +Set ownship of the current process to the uid specified in the +.Ar uid +parameter using +.Xr setuid 2 . +.It LOGIN_SETGROUP +Set group ownership of the current process to the group id +specified in the passwd structure using +.Xr setgid 2 , +and calls +.Xr initgroups 3 +to set up the group access list for the current process. +The +.Ar pwd +parameter must not be NULL if this option is used. +.It LOGIN_SETRESOURCES +Set resource limits for the current process based on values +specified in the system login class database. +Class capability tags used, with and without -cur (soft limit) +or -max (hard limit) suffixes and the corresponding resource +setting: +.Bd -literal +cputime RLIMIT_CPU +filesize RLIMIT_FSIZE +datasize RLIMIT_DATA +stacksize RLIMIT_STACK +coredumpsize RLIMIT_CORE +memoryuse RLIMIT_RSS +memorylocked RLIMIT_MEMLOCK +maxproc RLIMIT_NPROC +openfiles RLIMIT_NOFILE +sbsize RLIMIT_SBSIZE +.Ed +.It LOGIN_SETPRIORITY +Set the scheduling priority for the current process based on the +value specified in the system login class database. +Class capability tags used: +.Bd -literal +priority +.Ed +.It LOGIN_SETUMASK +Set the umask for the current process to a value in the user or +system login class database. +Class capability tags used: +.Bd -literal +umask +.Ed +.It LOGIN_SETPATH +Set the "path" and "manpath" environment variables based on values +in the user or system login class database. +Class capability tags used with the corresponding environment +variables set: +.Bd -literal +path PATH +manpath MANPATH +.Ed +.It LOGIN_SETENV +Set various environment variables based on values in the user or +system login class database. +Class capability tags used with the corresponding environment +variables set: +.Bd -literal +lang LANG +charset MM_CHARSET +timezone TZ +term TERM +.Ed +.Pp +Additional environment variables may be set using the list type +capability "setenv=var1 val1,var2 val2..,varN valN". +.It LOGIN_SETALL +Enables all of the above settings. +.El +.Pp +Note that when setting environment variables and a valid passwd +pointer is provided in the +.Ar pwd +parameter, the characters +.Ql \&~ +and +.Ql \&$ +are substituted for the user's home directory and login name +respectively. +.Pp +The +.Fn setclassresources +and +.Fn setclassenvironment +functions are subsets of the setcontext functions above, but may +be useful in isolation. +.Sh RETURN VALUES +.Fn setclasscontext +and +.Fn setusercontext +return -1 if an error occurred, or 0 on success. +If an error occurs when attempting to set the user, login, group +or resources, a message is reported to +.Xr syslog 3 , +with LOG_ERR priority and directed to the currently active facility. +.Sh SEE ALSO +.Xr setgid 2 , +.Xr setlogin 2 , +.Xr setuid 2 , +.Xr getcap 3 , +.Xr initgroups 3 , +.Xr login_cap 3 , +.Xr login.conf 5 , +.Xr termcap 5 diff --git a/lib/libutil/login_class.c b/lib/libutil/login_class.c new file mode 100644 index 0000000..b8b956b --- /dev/null +++ b/lib/libutil/login_class.c @@ -0,0 +1,408 @@ +/*- + * Copyright (c) 1996 by + * Sean Eric Fagan <sef@kithrup.com> + * David Nugent <davidn@blaze.net.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. This work was done expressly for inclusion into FreeBSD. Other use + * is permitted provided this notation is included. + * 4. Absolutely no warranty of function or purpose is made by the authors. + * 5. Modifications may be freely made to this file providing the above + * conditions are met. + * + * High-level routines relating to use of the user capabilities database + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <fcntl.h> +#include <pwd.h> +#include <syslog.h> +#include <login_cap.h> +#include <paths.h> +#include <sys/rtprio.h> + + +static struct login_res { + const char *what; + rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t); + int why; +} resources[] = { + { "cputime", login_getcaptime, RLIMIT_CPU }, + { "filesize", login_getcapsize, RLIMIT_FSIZE }, + { "datasize", login_getcapsize, RLIMIT_DATA }, + { "stacksize", login_getcapsize, RLIMIT_STACK }, + { "memoryuse", login_getcapsize, RLIMIT_RSS }, + { "memorylocked", login_getcapsize, RLIMIT_MEMLOCK }, + { "maxproc", login_getcapnum, RLIMIT_NPROC }, + { "openfiles", login_getcapnum, RLIMIT_NOFILE }, + { "coredumpsize", login_getcapsize, RLIMIT_CORE }, + { "sbsize", login_getcapsize, RLIMIT_SBSIZE }, + { NULL, 0, 0 } +}; + + +void +setclassresources(login_cap_t *lc) +{ + struct login_res *lr; + + if (lc == NULL) + return; + + for (lr = resources; lr->what != NULL; ++lr) { + struct rlimit rlim; + + /* + * The login.conf file can have <limit>, <limit>-max, and + * <limit>-cur entries. + * What we do is get the current current- and maximum- limits. + * Then, we try to get an entry for <limit> from the capability, + * using the current and max limits we just got as the + * default/error values. + * *Then*, we try looking for <limit>-cur and <limit>-max, + * again using the appropriate values as the default/error + * conditions. + */ + + if (getrlimit(lr->why, &rlim) != 0) + syslog(LOG_ERR, "getting %s resource limit: %m", lr->what); + else { + char name_cur[40]; + char name_max[40]; + rlim_t rcur = rlim.rlim_cur; + rlim_t rmax = rlim.rlim_max; + + sprintf(name_cur, "%s-cur", lr->what); + sprintf(name_max, "%s-max", lr->what); + + rcur = (*lr->who)(lc, lr->what, rcur, rcur); + 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); + } + } +} + + + +static struct login_vars { + const char *tag; + const char *var; + const char *def; +} pathvars[] = { + { "path", "PATH", NULL }, + { "cdpath", "CDPATH", NULL }, + { "manpath", "MANPATH", NULL }, + { NULL, NULL, NULL } +}, envars[] = { + { "lang", "LANG", NULL }, + { "charset", "MM_CHARSET", NULL }, + { "timezone", "TZ", NULL }, + { "term", "TERM", NULL }, + { NULL, NULL, NULL } +}; + +static char * +substvar(char * var, const struct passwd * pwd, int hlen, int pch, int nlen) +{ + char *np = NULL; + + if (var != NULL) { + int tildes = 0; + int dollas = 0; + char *p; + + if (pwd != NULL) { + /* Count the number of ~'s in var to substitute */ + p = var; + for (p = var; (p = strchr(p, '~')) != NULL; p++) + ++tildes; + /* Count the number of $'s in var to substitute */ + p = var; + for (p = var; (p = strchr(p, '$')) != NULL; p++) + ++dollas; + } + + np = malloc(strlen(var) + (dollas * nlen) + - dollas + (tildes * (pch+hlen)) + - tildes + 1); + + if (np != NULL) { + p = strcpy(np, var); + + if (pwd != NULL) { + /* + * This loop does user username and homedir substitutions + * for unescaped $ (username) and ~ (homedir) + */ + while (*(p += strcspn(p, "~$")) != '\0') { + int l = strlen(p); + + if (p > np && *(p-1) == '\\') /* Escaped: */ + memmove(p - 1, p, l + 1); /* Slide-out the backslash */ + else if (*p == '~') { + int v = pch && *(p+1) != '/'; /* Avoid double // */ + memmove(p + hlen + v, p + 1, l); /* Subst homedir */ + memmove(p, pwd->pw_dir, hlen); + if (v) + p[hlen] = '/'; + p += hlen + v; + } + else /* if (*p == '$') */ { + memmove(p + nlen, p + 1, l); /* Subst username */ + memmove(p, pwd->pw_name, nlen); + p += nlen; + } + } + } + } + } + + return np; +} + + +void +setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths) +{ + struct login_vars *vars = paths ? pathvars : envars; + int hlen = pwd ? strlen(pwd->pw_dir) : 0; + int nlen = pwd ? strlen(pwd->pw_name) : 0; + char pch = 0; + + if (hlen && pwd->pw_dir[hlen-1] != '/') + ++pch; + + while (vars->tag != NULL) { + 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) { + setenv(vars->var, np, 1); + free(np); + } else if (vars->def != NULL) { + setenv(vars->var, vars->def, 0); + } + ++vars; + } + + /* + * If we're not processing paths, then see if there is a setenv list by + * which the admin and/or user may set an arbitrary set of env vars. + */ + if (!paths) { + char **set_env = login_getcaplist(lc, "setenv", ","); + + if (set_env != NULL) { + while (*set_env != NULL) { + char *p = strchr(*set_env, '='); + + if (p != NULL) { /* Discard invalid entries */ + char *np; + + *p++ = '\0'; + if ((np = substvar(p, pwd, hlen, pch, nlen)) != NULL) { + setenv(*set_env, np, 1); + free(np); + } + } + ++set_env; + } + } + } +} + + +/* + * setclasscontext() + * + * For the login class <class>, set various class context values + * (limits, mainly) to the values for that class. Which values are + * set are controlled by <flags> -- see <login_class.h> for the + * possible values. + * + * setclasscontext() can only set resources, priority, and umask. + */ + +int +setclasscontext(const char *classname, unsigned int flags) +{ + int rc; + login_cap_t *lc; + + lc = login_getclassbyname(classname, NULL); + + flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY | + LOGIN_SETUMASK | LOGIN_SETPATH; + + rc = lc ? setusercontext(lc, NULL, 0, flags) : -1; + login_close(lc); + return rc; +} + + + +/* + * Private functionw which takes care of processing + */ + +static mode_t +setlogincontext(login_cap_t *lc, const struct passwd *pwd, + mode_t mymask, unsigned long flags) +{ + if (lc) { + /* Set resources */ + if (flags & LOGIN_SETRESOURCES) + setclassresources(lc); + /* See if there's a umask override */ + if (flags & LOGIN_SETUMASK) + mymask = (mode_t)login_getcapnum(lc, "umask", mymask, mymask); + /* Set paths */ + if (flags & LOGIN_SETPATH) + setclassenvironment(lc, pwd, 1); + /* Set environment */ + if (flags & LOGIN_SETENV) + setclassenvironment(lc, pwd, 0); + } + return mymask; +} + + + +/* + * setusercontext() + * + * Given a login class <lc> and a user in <pwd>, with a uid <uid>, + * set the context as in setclasscontext(). <flags> controls which + * values are set. + * + * The difference between setclasscontext() and setusercontext() is + * that the former sets things up for an already-existing process, + * while the latter sets things up from a root context. Such as might + * be called from login(1). + * + */ + +int +setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned int flags) +{ + quad_t p; + mode_t mymask; + login_cap_t *llc = NULL; +#ifndef __NETBSD_SYSCALLS + struct rtprio rtp; +#endif + + if (lc == NULL) { + if (pwd != NULL && (lc = login_getpwclass(pwd)) != NULL) + llc = lc; /* free this when we're done */ + } + + if (flags & LOGIN_SETPATH) + pathvars[0].def = uid ? _PATH_DEFPATH : _PATH_STDPATH; + + /* we need a passwd entry to set these */ + if (pwd == NULL) + flags &= ~(LOGIN_SETGROUP | LOGIN_SETLOGIN); + + /* Set the process priority */ + if (flags & LOGIN_SETPRIORITY) { + p = login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI); + + if(p > PRIO_MAX) { +#ifndef __NETBSD_SYSCALLS + rtp.type = RTP_PRIO_IDLE; + rtp.prio = p - PRIO_MAX - 1; + p = (rtp.prio > RTP_PRIO_MAX) ? 31 : p; + if(rtprio(RTP_SET, 0, &rtp)) + syslog(LOG_WARNING, "rtprio '%s' (%s): %m", + pwd->pw_name, lc ? lc->lc_class : LOGIN_DEFCLASS); +#endif + } else if(p < PRIO_MIN) { +#ifndef __NETBSD_SYSCALLS + rtp.type = RTP_PRIO_REALTIME; + rtp.prio = abs(p - PRIO_MIN + RTP_PRIO_MAX); + p = (rtp.prio > RTP_PRIO_MAX) ? 1 : p; + if(rtprio(RTP_SET, 0, &rtp)) + syslog(LOG_WARNING, "rtprio '%s' (%s): %m", + pwd->pw_name, lc ? lc->lc_class : LOGIN_DEFCLASS); +#endif + } else { + if (setpriority(PRIO_PROCESS, 0, (int)p) != 0) + syslog(LOG_WARNING, "setpriority '%s' (%s): %m", + pwd->pw_name, lc ? lc->lc_class : LOGIN_DEFCLASS); + } + } + + /* Setup the user's group permissions */ + if (flags & LOGIN_SETGROUP) { + if (setgid(pwd->pw_gid) != 0) { + syslog(LOG_ERR, "setgid(%lu): %m", (u_long)pwd->pw_gid); + login_close(llc); + 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; + } + } + + /* Set the sessions login */ + if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) { + syslog(LOG_ERR, "setlogin(%s): %m", pwd->pw_name); + login_close(llc); + return -1; + } + + mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0; + 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 */ + } + + /* + * 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); + login_close(lc); + } + + /* Finally, set any umask we've found */ + if (flags & LOGIN_SETUMASK) + umask(mymask); + + return 0; +} + diff --git a/lib/libutil/login_crypt.c b/lib/libutil/login_crypt.c new file mode 100644 index 0000000..f3d83a8 --- /dev/null +++ b/lib/libutil/login_crypt.c @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2000 Brian Fundakowski Feldman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> + +#include <login_cap.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.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); + if (getenv("CRYPT_DEBUG") != NULL) + fprintf(stderr, "login_setcryptfmt: " + "passwd_format = %s\n", cipher); + if (cipher == NULL) + return (error); + if (!crypt_set_format(cipher)) + return (error); + return (cipher); +} diff --git a/lib/libutil/login_ok.3 b/lib/libutil/login_ok.3 new file mode 100644 index 0000000..c7fa84d --- /dev/null +++ b/lib/libutil/login_ok.3 @@ -0,0 +1,140 @@ +.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, is permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice immediately at the beginning of the file, without modification, +.\" this list of conditions, and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. This work was done expressly for inclusion into FreeBSD. Other use +.\" is permitted provided this notation is included. +.\" 4. Absolutely no warranty of function or purpose is made by the author +.\" David Nugent. +.\" 5. Modifications may be freely made to this file providing the above +.\" conditions are met. +.\" +.\" $FreeBSD$ +.\" +.Dd January 2, 1997 +.Os +.Dt LOGIN_OK 3 +.Sh NAME +.Nm auth_ttyok , +.Nm auth_hostok , +.Nm auth_timeok +.Nd functions for checking login class based login restrictions +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In time.h +.In login_cap.h +.Ft int +.Fn auth_ttyok "login_cap_t *lc" "const char *tty" +.Ft int +.Fn auth_hostok "login_cap_t *lc" "const char *host" "char const *ip" +.Ft int +.Fn auth_timeok "login_cap_t *lc" "time_t t" +.Sh DESCRIPTION +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 +.Fn auth_ttyok +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 +the +.Em ttys.deny +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 +.Em ttys.deny +list exists and is non-empty, and the device or its +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*), +or may name a ttygroup, when group=<name> tags have been assigned in +.Pa /etc/ttys . +Matching of ttys and ttygroups is case sensitive. +Passing a +.Dv NULL +or empty string as the +.Ar tty +parameter causes the function to return a non-zero value. +.Pp +.Fn auth_hostok +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 +and +.Em host.deny +login class capabilities. +As with ttys and their groups, wildcards and character classes may be +used in the host allow and deny capability records. +The +.Xr fnmatch 3 +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 +is in its canonical form. +No hostname or address lookups are attempted. +.Pp +It is possible to call this function with either the hostname or +the IP address missing (i.e.\& +.Dv NULL ) +and matching will be performed +only on the basis of the parameter given. +Passing +.Dv NULL +or empty strings in both parameters will result in +a non-zero return value. +.Pp +The +.Fn auth_timeok +function checks to see that a given time value is within the +.Em times.allow +login class capability and not within the +.Em times.deny +access lists. +An empty or non-existent +.Em times.allow +list allows access at any +time, except if a given time is falls within a period in the +.Em times.deny +list. +The format of time period records contained in both +.Em times.allow +and +.Em times.deny +capability fields is explained in detail in the +.Xr login_times 3 +manual page. +.Sh RETURN VALUES +A non-zero return value from any of these functions indicates that +login access is granted. +A zero return value means either that the item being tested is not +in the +.Em allow +access list, or is within the +.Em deny +access list. +.Sh SEE ALSO +.Xr getcap 3 , +.Xr login_cap 3 , +.Xr login_class 3 , +.Xr login_times 3 , +.Xr login.conf 5 , +.Xr termcap 5 diff --git a/lib/libutil/login_ok.c b/lib/libutil/login_ok.c new file mode 100644 index 0000000..e66110c --- /dev/null +++ b/lib/libutil/login_ok.c @@ -0,0 +1,251 @@ +/*- + * Copyright (c) 1996 by + * David Nugent <davidn@blaze.net.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. This work was done expressly for inclusion into FreeBSD. Other use + * is permitted provided this notation is included. + * 4. Absolutely no warranty of function or purpose is made by the authors. + * 5. Modifications may be freely made to this file providing the above + * conditions are met. + * + * Support allow/deny lists in login class capabilities + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <ttyent.h> +#include <fnmatch.h> + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/param.h> +#include <login_cap.h> + + +/* -- support functions -- */ + +/* + * login_strinlist() + * This function is intentionally public - reused by TAS. + * Returns TRUE (non-zero) if a string matches a pattern + * in a given array of patterns. 'flags' is passed directly + * to fnmatch(3). + */ + +int +login_strinlist(char **list, char const *str, int flags) +{ + int rc = 0; + + if (str != NULL && *str != '\0') { + int i = 0; + + while (rc == 0 && list[i] != NULL) + rc = fnmatch(list[i++], str, flags) == 0; + } + return rc; +} + + +/* + * login_str2inlist() + * Locate either or two strings in a given list + */ + +int +login_str2inlist(char **ttlst, const char *str1, const char *str2, int flags) +{ + int rc = 0; + + if (login_strinlist(ttlst, str1, flags)) + rc = 1; + else if (login_strinlist(ttlst, str2, flags)) + rc = 1; + return rc; +} + + +/* + * login_timelist() + * This function is intentinoally public - reused by TAS. + * Returns an allocated list of time periods given an array + * of time periods in ascii form. + */ + +login_time_t * +login_timelist(login_cap_t *lc, char const *cap, int *ltno, + login_time_t **ltptr) +{ + int j = 0; + struct login_time *lt = NULL; + char **tl; + + if ((tl = login_getcaplist(lc, cap, NULL)) != NULL) { + + while (tl[j++] != NULL) + ; + if (*ltno >= j) + lt = *ltptr; + else if ((lt = realloc(*ltptr, j * sizeof(struct login_time))) != NULL) { + *ltno = j; + *ltptr = lt; + } + if (lt != NULL) { + int i = 0; + + for (--j; i < j; i++) + lt[i] = parse_lt(tl[i]); + lt[i].lt_dow = LTM_NONE; + } + } + return lt; +} + + +/* + * login_ttyok() + * This function is a variation of auth_ttyok(), but it checks two + * arbitrary capability lists not necessarily related to access. + * This hook is provided for the accounted/exclude accounting lists. + */ + +int +login_ttyok(login_cap_t *lc, const char *tty, const char *allowcap, + const char *denycap) +{ + int rc = 1; + + if (lc != NULL && tty != NULL && *tty != '\0') { + struct ttyent *te; + char *grp; + char **ttl; + + te = getttynam(tty); /* Need group name */ + grp = te ? te->ty_group : NULL; + ttl = login_getcaplist(lc, allowcap, NULL); + + if (ttl != NULL && !login_str2inlist(ttl, tty, grp, 0)) + rc = 0; /* tty or ttygroup not in allow list */ + else { + + ttl = login_getcaplist(lc, denycap, NULL); + if (ttl != NULL && login_str2inlist(ttl, tty, grp, 0)) + rc = 0; /* tty or ttygroup in deny list */ + } + } + + return rc; +} + + +/* + * auth_ttyok() + * Determine whether or not login on a tty is accessible for + * a login class + */ + +int +auth_ttyok(login_cap_t *lc, const char * tty) +{ + return login_ttyok(lc, tty, "ttys.allow", "ttys.deny"); +} + + +/* + * login_hostok() + * This function is a variation of auth_hostok(), but it checks two + * arbitrary capability lists not necessarily related to access. + * This hook is provided for the accounted/exclude accounting lists. + */ + +int +login_hostok(login_cap_t *lc, const char *host, const char *ip, + const char *allowcap, const char *denycap) +{ + int rc = 1; /* Default is ok */ + + if (lc != NULL && + ((host != NULL && *host != '\0') || (ip != NULL && *ip != '\0'))) { + char **hl; + + hl = login_getcaplist(lc, allowcap, NULL); + if (hl != NULL && !login_str2inlist(hl, host, ip, FNM_CASEFOLD)) + rc = 0; /* host or IP not in allow list */ + else { + + hl = login_getcaplist(lc, denycap, NULL); + if (hl != NULL && login_str2inlist(hl, host, ip, FNM_CASEFOLD)) + rc = 0; /* host or IP in deny list */ + } + } + + return rc; +} + + +/* + * auth_hostok() + * Determine whether or not login from a host is ok + */ + +int +auth_hostok(login_cap_t *lc, const char *host, const char *ip) +{ + return login_hostok(lc, host, ip, "host.allow", "host.deny"); +} + + +/* + * auth_timeok() + * Determine whether or not login is ok at a given time + */ + +int +auth_timeok(login_cap_t *lc, time_t t) +{ + int rc = 1; /* Default is ok */ + + if (lc != NULL && t != (time_t)0 && t != (time_t)-1) { + struct tm *tptr; + + static int ltimesno = 0; + static struct login_time *ltimes = NULL; + + if ((tptr = localtime(&t)) != NULL) { + struct login_time *lt; + + lt = login_timelist(lc, "times.allow", <imesno, <imes); + if (lt != NULL && in_ltms(lt, tptr, NULL) == -1) + rc = 0; /* not in allowed times list */ + else { + + lt = login_timelist(lc, "times.deny", <imesno, <imes); + if (lt != NULL && in_ltms(lt, tptr, NULL) != -1) + rc = 0; /* in deny times list */ + } + if (ltimes) { + free(ltimes); + ltimes = NULL; + ltimesno = 0; + } + } + } + + return rc; +} diff --git a/lib/libutil/login_times.3 b/lib/libutil/login_times.3 new file mode 100644 index 0000000..1082404 --- /dev/null +++ b/lib/libutil/login_times.3 @@ -0,0 +1,157 @@ +.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, is permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice immediately at the beginning of the file, without modification, +.\" this list of conditions, and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. This work was done expressly for inclusion into FreeBSD. Other use +.\" is permitted provided this notation is included. +.\" 4. Absolutely no warranty of function or purpose is made by the author +.\" David Nugent. +.\" 5. Modifications may be freely made to this file providing the above +.\" conditions are met. +.\" +.\" $FreeBSD$ +.\" +.Dd January 2, 1997 +.Os +.Dt LOGIN_TIMES 3 +.Sh NAME +.Nm parse_lt , +.Nm in_ltm , +.Nm in_ltms +.Nd functions for parsing and checking login time periods +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In time.h +.In login_cap.h +.Ft login_time_t +.Fn parse_lt "const char *str" +.Ft int +.Fn in_ltm "const login_time_t *lt" "struct tm *t" "time_t *ends" +.Ft int +.Fn in_ltms "const login_time_t *lt" "struct tm *t" "time_t *ends" +.Sh DESCRIPTION +This set of functions may be used for parsing and checking login and +session times against a predefined list of allowed login times as +used in +.Xr login.conf 5 . +.Pp +The format of allowed and disallowed session times specified in the +.Ar times.allow +and +.Ar times.deny +capability fields in a login class are comprised of a prefix which +specifies one or more 2- or 3-character day codes, followed by +a start and end time in 24 hour format separated by a hyphen. +Day codes may be concatenated together to select specific days, or +the special mnemonics "Any" and "All" (for any/all days of the week), +"Wk" for any day of the week (excluding Saturdays and Sundays) and +"Wd" for any weekend day may be used. +.Pp +For example, the following time period: +.Dl MoThFrSa1400-2200 +is interpreted as Monday, Thursday through Saturday between the hours +of 2pm and 10pm. +.Dl Wd0600-1800 +means Saturday and Sunday, between the hours of 6am through 6pm, and +.Dl Any0400-1600 +means any day of the week, between 4am and 4pm. +.Pp +Note that all time periods reference system local time. +.Pp +The +.Fn parse_lt +function converts the ASCII representation of a time period into +a structure of type +.Ft login_time_t . +This is defined as: +.Bd -literal +typedef struct login_time +{ + u_short lt_start; /* Start time */ + u_short lt_end; /* End time */ + u_char lt_dow; /* Days of week */ +} login_time_t; +.Ed +.Pp +The +.Ar lt_start +and +.Ar lt_end +fields contain the number of minutes past midnight at which the +described period begins and ends. +The +.Ar lt_dow +field is a bit field, containing one bit for each day of the week +and one bit unused. +A series +.Em LTM_* +macros may be used for testing bits individually and in combination. +If no bits are set in this field - ie. it contains the value +.Em LTM_NONE +- then the entire period is assumed invalid. +This is used as a convention to mark the termination of an array +of login_time_t values. +If +.Fn parse_lt +returns a +.Ar login_time_t +with +.Ar lt_dow +equal to +.Em LTM_NONE +then a parsing error was encountered. +.Pp +The remaining functions provide the ability to test a given time_t or +struct tm value against a specific time period or array of time +periods. +.Fn in_ltm +determines whether the given time described by the struct tm +passed as the second parameter falls within the period described +by the first parameter. +A boolean value is returned, indicating whether or not the time +specified falls within the period. +If the time does fall within the time period, and the third +parameter to the function is not NULL, the time at which the +period ends relative to the time passed is returned. +.Pp +The +.Fn in_ltms +function is similar to +.Fn in_ltm +except that the first parameter must be a pointer to an array +of login_time_t objects, which is up to LC_MAXTIMES (64) +elements in length, and terminated by an element with its +.Ar lt_dow +field set to +.Em LTM_NONE . +.Sh RETURN VALUES +.Fn parse_lt +returns a filled in structure of type login_time_t containing the +parsed time period. +If a parsing error occurs, the lt_dow field is set to +.Em LTM_NONE +(i.e. 0). +.Pp +.Fn in_ltm +returns non-zero if the given time falls within the period described +by the login_time_t passed as the first parameter. +.Pp +.Fn in_ltms +returns the index of the first time period found in which the given +time falls, or -1 if none of them apply. +.Sh SEE ALSO +.Xr getcap 3 , +.Xr login_cap 3 , +.Xr login_class 3 , +.Xr login.conf 5 , +.Xr termcap 5 diff --git a/lib/libutil/login_times.c b/lib/libutil/login_times.c new file mode 100644 index 0000000..add9135 --- /dev/null +++ b/lib/libutil/login_times.c @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 1996 by + * David Nugent <davidn@blaze.net.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. This work was done expressly for inclusion into FreeBSD. Other use + * is permitted provided this notation is included. + * 4. Absolutely no warranty of function or purpose is made by the authors. + * 5. Modifications may be freely made to this file providing the above + * conditions are met. + * + * Login period parsing and comparison functions. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <ctype.h> + +#include <sys/types.h> +#include <login_cap.h> + +static struct +{ + const char *dw; + u_char cn; + u_char fl; +} dws[] = +{ + { "su", 2, LTM_SUN }, { "mo", 2, LTM_MON }, { "tu", 2, LTM_TUE }, + { "we", 2, LTM_WED }, { "th", 2, LTM_THU }, { "fr", 2, LTM_FRI }, + { "sa", 2, LTM_SAT }, { "any",3, LTM_ANY }, { "all",3, LTM_ANY }, + { "wk", 2, LTM_WK }, { "wd", 2, LTM_WD }, { NULL, 0, 0 } +}; + +static char * +parse_time(char * ptr, u_short * t) +{ + u_short val; + + for (val = 0; *ptr && isdigit(*ptr); ptr++) + val = (u_short)(val * 10 + (*ptr - '0')); + + *t = (u_short)((val / 100) * 60 + (val % 100)); + + return ptr; +} + + +login_time_t +parse_lt(const char * str) +{ + login_time_t t; + + memset(&t, 0, sizeof t); + t.lt_dow = LTM_NONE; + if (str && *str && strcmp(str, "Never") != 0 && strcmp(str, "None") != 0) { + int i; + login_time_t m = t; + char *p; + char buf[64]; + + /* Make local copy and force lowercase to simplify parsing */ + p = strncpy(buf, str, sizeof buf); + buf[sizeof buf - 1] = '\0'; + for (i = 0; buf[i]; i++) + buf[i] = (char)tolower(buf[i]); + + while (isalpha(*p)) { + + i = 0; + while (dws[i].dw && strncmp(p, dws[i].dw, dws[i].cn) != 0) + i++; + if (dws[i].dw == NULL) + break; + m.lt_dow |= dws[i].fl; + p += dws[i].cn; + } + + if (m.lt_dow == LTM_NONE) /* No (valid) prefix, assume any */ + m.lt_dow |= LTM_ANY; + + if (isdigit(*p)) + p = parse_time(p, &m.lt_start); + else + m.lt_start = 0; + if (*p == '-') + p = parse_time(++p, &m.lt_end); + else + m.lt_end = 1440; + + t = m; + } + return t; +} + + +int +in_ltm(const login_time_t * ltm, struct tm * tt, time_t * ends) +{ + int rc = 0; + + if (tt != NULL) { + /* First, examine the day of the week */ + if ((u_char)(0x01 << tt->tm_wday) & ltm->lt_dow) { + /* Convert `current' time to minute of the day */ + u_short now = (u_short)((tt->tm_hour * 60) + tt->tm_min); + + if (tt->tm_sec > 30) + ++now; + if (now >= ltm->lt_start && now < ltm->lt_end) { + rc = 2; + if (ends != NULL) { + /* If requested, return ending time for this period */ + tt->tm_hour = (int)(ltm->lt_end / 60); + tt->tm_min = (int)(ltm->lt_end % 60); + *ends = mktime(tt); + } + } + } + } + return rc; +} + + +int +in_lt(const login_time_t * ltm, time_t * t) +{ + return in_ltm(ltm, localtime(t), t); +} + +int +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; + i++; + } + return -1; +} + +int +in_lts(const login_time_t * ltm, time_t * t) +{ + return in_ltms(ltm, localtime(t), t); +} + diff --git a/lib/libutil/login_tty.3 b/lib/libutil/login_tty.3 new file mode 100644 index 0000000..af3eaaf --- /dev/null +++ b/lib/libutil/login_tty.3 @@ -0,0 +1,62 @@ +.\" +.\" Copyright (c) 1996 Joerg Wunsch +.\" +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" " +.Dd December 29, 1996 +.Os +.Dt LOGIN_TTY 3 +.Sh NAME +.Nm login_tty +.Nd prepare a tty for a new login session +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In libutil.h +.Ft int +.Fn login_tty "int fd" +.Sh DESCRIPTION +The function +.Fn login_tty +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 +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 +.Ar fd +the controlling terminal of the calling process, and 0 otherwise. +.Sh SEE ALSO +.Xr dup2 2 , +.Xr ioctl 2 , +.Xr setsid 2 , +.Xr tty 4 diff --git a/lib/libutil/login_tty.c b/lib/libutil/login_tty.c new file mode 100644 index 0000000..5981198 --- /dev/null +++ b/lib/libutil/login_tty.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)login_tty.c 8.1 (Berkeley) 6/4/93"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/ioctl.h> + +#include <unistd.h> +#include <stdlib.h> +#include <libutil.h> + +int +login_tty(fd) + int fd; +{ + (void) setsid(); + if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1) + return (-1); + (void) dup2(fd, 0); + (void) dup2(fd, 1); + (void) dup2(fd, 2); + if (fd > 2) + (void) close(fd); + return (0); +} diff --git a/lib/libutil/logout.3 b/lib/libutil/logout.3 new file mode 100644 index 0000000..d5beb7f --- /dev/null +++ b/lib/libutil/logout.3 @@ -0,0 +1,67 @@ +.\" +.\" Copyright (c) 1996 Joerg Wunsch +.\" +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" " +.Dd December 29, 1996 +.Os +.Dt LOGOUT 3 +.Sh NAME +.Nm logout +.Nd remove an entry from the utmp file +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In libutil.h +.Ft int +.Fn logout "const char *line" +.Sh DESCRIPTION +The function +.Fn logout +searches the +.Xr utmp 5 +file for the slot described by +.Ar line +(usually a tty name). If such a slot could be found, it will be updated +with a record where the +.Em name +and +.Em host +fields are empty, and the time stamp field is updated to the current time. +.Sh RETURN VALUES +.Fn Logout +returns 1 if the slot described by +.Ar line +has been found and updated, 0 otherwise. +.Sh SEE ALSO +.Xr login 3 , +.Xr utmp 5 , +.Xr wtmp 5 +.Sh BUGS +The calling interface of +.Fn logout +is inconsistent with that of +.Xr login 3 . diff --git a/lib/libutil/logout.c b/lib/libutil/logout.c new file mode 100644 index 0000000..b3341f1 --- /dev/null +++ b/lib/libutil/logout.c @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)logout.c 8.1 (Berkeley) 6/4/93"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/time.h> + +#include <fcntl.h> +#include <utmp.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <libutil.h> + +typedef struct utmp UTMP; + +int +logout(line) + const char *line; +{ + int fd; + UTMP ut; + int rval; + + if ((fd = open(_PATH_UTMP, O_RDWR, 0)) < 0) + return(0); + rval = 0; + while (read(fd, &ut, sizeof(UTMP)) == sizeof(UTMP)) { + if (!ut.ut_name[0] || strncmp(ut.ut_line, line, UT_LINESIZE)) + continue; + bzero(ut.ut_name, UT_NAMESIZE); + bzero(ut.ut_host, UT_HOSTSIZE); + (void)time(&ut.ut_time); + (void)lseek(fd, -(off_t)sizeof(UTMP), L_INCR); + (void)write(fd, &ut, sizeof(UTMP)); + rval = 1; + } + (void)close(fd); + return(rval); +} diff --git a/lib/libutil/logwtmp.3 b/lib/libutil/logwtmp.3 new file mode 100644 index 0000000..16903fb --- /dev/null +++ b/lib/libutil/logwtmp.3 @@ -0,0 +1,71 @@ +.\" +.\" Copyright (c) 1996 Joerg Wunsch +.\" +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" " +.Dd December 29, 1996 +.Os +.Dt LOGWTMP 3 +.Sh NAME +.Nm logwtmp +.Nd append a new record to the wtmp file +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In libutil.h +.Ft void +.Fn logwtmp "const char *line" "const char *name" "const char *host" +.Sh DESCRIPTION +The function +.Fn logwtmp +tries to append a new record to the +.Xr wtmp 5 +file, using the provided arguments +.Ar line , +.Ar name , +and +.Ar host , +and the current time. +.Pp +If the length of the hostname string +.Ar host +is longer than what would fit into the hostname field of the +.Xr wtmp 5 +file, it will first be attempted to convert it into a numerical IP +address using +.Xr gethostbyname 3 . +Failing this, the hostname will be recorded as +.Qq invalid hostname . +.Pp +The calling process must have permission to write to the +.Xr wtmp 5 +file. +.Sh RETURN VALUES +None. +.Sh SEE ALSO +.Xr gethostbyname 3 , +.Xr login 3 , +.Xr wtmp 5 diff --git a/lib/libutil/logwtmp.c b/lib/libutil/logwtmp.c new file mode 100644 index 0000000..ac407ea --- /dev/null +++ b/lib/libutil/logwtmp.c @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)logwtmp.c 8.1 (Berkeley) 6/4/93"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/file.h> +#include <sys/socket.h> +#include <sys/stat.h> + +#include <libutil.h> +#include <netdb.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <utmp.h> + +/* wrapper for KAME-special getnameinfo() */ +#ifndef NI_WITHSCOPEID +#define NI_WITHSCOPEID 0 +#endif + + +void +logwtmp(line, name, host) + const char *line; + const char *name; + const char *host; +{ + struct utmp ut; + struct stat buf; + char fullhost[MAXHOSTNAMELEN]; + int fd; + + strncpy(fullhost, host, sizeof(fullhost) - 1); + fullhost[sizeof(fullhost) - 1] = '\0'; + trimdomain(fullhost, UT_HOSTSIZE); + host = fullhost; + + if (strlen(host) > UT_HOSTSIZE) { + int error; + struct addrinfo hints, *res; + + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_CANONNAME; + error = getaddrinfo(host, NULL, &hints, &res); + if (error != 0 || res->ai_addr == NULL) + host = "invalid hostname"; + else { + error = getnameinfo(res->ai_addr, res->ai_addrlen, + fullhost, strlen(fullhost), NULL, 0, + NI_NUMERICHOST|NI_WITHSCOPEID); + if (error != 0) { + fprintf(stderr, "%d", error); + host = "invalid hostname"; + } + } + } + + if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0) + return; + if (fstat(fd, &buf) == 0) { + (void) strncpy(ut.ut_line, line, sizeof(ut.ut_line)); + (void) strncpy(ut.ut_name, name, sizeof(ut.ut_name)); + (void) strncpy(ut.ut_host, host, sizeof(ut.ut_host)); + (void) time(&ut.ut_time); + if (write(fd, (char *)&ut, sizeof(struct utmp)) != + sizeof(struct utmp)) + (void) ftruncate(fd, buf.st_size); + } + (void) close(fd); +} diff --git a/lib/libutil/property.3 b/lib/libutil/property.3 new file mode 100644 index 0000000..219c0e7 --- /dev/null +++ b/lib/libutil/property.3 @@ -0,0 +1,94 @@ +.\" +.\" Copyright (c) 1998 Jordan Hubbard +.\" +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" " +.Dd October 7, 1998 +.Os +.Dt PROPERTIES 3 +.Sh NAME +.Nm properties_read , +.Nm propery_find , +.Nm properties_free +.Nd "functions to allow creating simple property lists from ASCII file data" +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In libutil.h +.Ft properties +.Fn properties_read "int fd" +.Ft char * +.Fn property_find "properties list" "const char *name" +.Ft void +.Fn properties_free "properties list" +.Sh DESCRIPTION +.Bd -literal +typedef struct _properties { + struct _properties *next; + char *name; + char *value; +} *properties; +.Ed +.Pp +The function +.Fn properties_read +reads +.Fa name = value +pairs from the file descriptor passed in +.Fa fd +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 +.Fn property_find +Returns the associated value string for the property named +.Fa name +if found, otherwise NULL. The value returned may be up to +.Dv PROPERTY_MAX_VALUE +bytes in length. +.Pp +.Fn properties_free +is used to free the structure returned by +.Fn properties_read +when it is no longer needed. +.Sh FILE FORMAT +Each property in the file is assumed to have the format of +.Fa name = value +where +.Fa name +is an alphanumeric string (and any punctuation not including the `=' character) +and +.Fa value +is an arbitary 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 +be a comment and will be ignored. +.Sh SEE ALSO +.Xr auth_getval 3 +.Sh BUGS +Simplistic. +.Sh AUTHORS +.An Jordan Hubbard diff --git a/lib/libutil/property.c b/lib/libutil/property.c new file mode 100644 index 0000000..815ce6c --- /dev/null +++ b/lib/libutil/property.c @@ -0,0 +1,228 @@ +/* + * + * Simple property list handling code. + * + * Copyright (c) 1998 + * Jordan Hubbard. 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, + * verbatim and that no modifications are made prior to this + * point in the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 HIS PETS 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, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <ctype.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <sys/types.h> +#include <libutil.h> + +static properties +property_alloc(char *name, char *value) +{ + properties n; + + n = (properties)malloc(sizeof(struct _property)); + n->next = NULL; + n->name = name ? strdup(name) : NULL; + n->value = value ? strdup(value) : NULL; + return n; +} + +properties +properties_read(int fd) +{ + properties head, ptr; + char hold_n[PROPERTY_MAX_NAME + 1]; + 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; + int ch = 0, blevel = 0; + + n = v = bp = max = 0; + head = ptr = NULL; + state = LOOK; + while (state != STOP) { + if (state != COMMIT) { + if (bp == max) + state = FILL; + else + ch = buf[bp++]; + } + switch(state) { + case FILL: + if ((max = read(fd, buf, sizeof buf)) <= 0) { + state = STOP; + break; + } + else { + state = LOOK; + ch = buf[0]; + bp = 1; + } + /* Fall through deliberately since we already have a character and state == LOOK */ + + case LOOK: + if (isspace(ch)) + continue; + /* Allow shell or lisp style comments */ + else if (ch == '#' || ch == ';') { + state = COMMENT; + continue; + } + else if (isalnum(ch) || ch == '_') { + if (n >= PROPERTY_MAX_NAME) { + n = 0; + state = COMMENT; + } + else { + hold_n[n++] = ch; + state = NAME; + } + } + else + state = COMMENT; /* Ignore the rest of the line */ + break; + + case COMMENT: + if (ch == '\n') + state = LOOK; + break; + + case NAME: + if (ch == '\n' || !ch) { + hold_n[n] = '\0'; + hold_v[0] = '\0'; + v = n = 0; + state = COMMIT; + } + else if (isspace(ch)) + continue; + else if (ch == '=') { + hold_n[n] = '\0'; + v = n = 0; + state = VALUE; + } + else + hold_n[n++] = ch; + break; + + case VALUE: + if (v == 0 && ch == '\n') { + hold_v[v] = '\0'; + v = n = 0; + state = COMMIT; + } + else if (v == 0 && isspace(ch)) + continue; + else if (ch == '{') { + state = MVALUE; + ++blevel; + } + else if (ch == '\n' || !ch) { + hold_v[v] = '\0'; + v = n = 0; + state = COMMIT; + } + else { + if (v >= PROPERTY_MAX_VALUE) { + state = COMMENT; + v = n = 0; + break; + } + else + hold_v[v++] = ch; + } + break; + + case MVALUE: + /* multiline value */ + if (v >= PROPERTY_MAX_VALUE) { + warn("properties_read: value exceeds max length"); + state = COMMENT; + n = v = 0; + } + else if (ch == '}' && !--blevel) { + hold_v[v] = '\0'; + v = n = 0; + state = COMMIT; + } + else { + hold_v[v++] = ch; + if (ch == '{') + ++blevel; + } + break; + + case COMMIT: + if (!head) + head = ptr = property_alloc(hold_n, hold_v); + else { + ptr->next = property_alloc(hold_n, hold_v); + ptr = ptr->next; + } + state = LOOK; + v = n = 0; + break; + + case STOP: + /* we don't handle this here, but this prevents warnings */ + break; + } + } + 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; + list = list->next; + } + return NULL; +} + +void +properties_free(properties list) +{ + properties tmp; + + while (list) { + tmp = list->next; + if (list->name) + free(list->name); + if (list->value) + free(list->value); + free(list); + list = tmp; + } +} diff --git a/lib/libutil/pty.3 b/lib/libutil/pty.3 new file mode 100644 index 0000000..30c9f96 --- /dev/null +++ b/lib/libutil/pty.3 @@ -0,0 +1,140 @@ +.\" +.\" Copyright (c) 1996 Joerg Wunsch +.\" +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" " +.Dd December 29, 1996 +.Os +.Dt PTY 3 +.Sh NAME +.Nm openpty , +.Nm forkpty +.Nd auxiliary functions to obtain a pseudo-terminal +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In sys/ioctl.h +.In termios.h +.In libutil.h +.Ft int +.Fn openpty "int *amaster" "int *aslave" "char *name" "struct termios *termp" "struct winsize *winp" +.Ft int +.Fn forkpty "int *amaster" "char *name" "struct termios *termp" "struct winsize *winp" +.Sh DESCRIPTION +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 +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 +.Xr revoke 2 . +.Pp +If the argument +.Fa name +is not +.Dv NULL , +.Fn openpty +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 +.Fa termp +or +.Fa winp +are not +.Dv NULL , +.Fn openpty +initializes the termios and window size settings from the structures +these arguments point to, respectively. +.Pp +Upon return, the open file descriptors for the master and slave side +of the pty are returned in the locations pointed to by +.Fa amaster +and +.Fa aslave , +respectively. +.Pp +.Fn Forkpty +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 +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 +.Fa amaster , +.Fa name , +.Fa termp , +and +.Fa winp +have the same meaning as described for +.Fn openpty . +.Sh RETURN VALUES +.Fn Openpty +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. +.Sh ERRORS +On failure, +.Fn openpty +will set the global variable +.Dv errno +to +.Er ENOENT . +.Pp +In addition to this, +.Fn forkpty +may set it to any value as described for +.Xr fork 2 . +.Sh SEE ALSO +.Xr chmod 2 , +.Xr chown 2 , +.Xr fork 2 , +.Xr getuid 2 , +.Xr open 2 , +.Xr revoke 2 , +.Xr login_tty 3 , +.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 new file mode 100644 index 0000000..088ea8d --- /dev/null +++ b/lib/libutil/pty.c @@ -0,0 +1,135 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)pty.c 8.3 (Berkeley) 5/16/94"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> + +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> +#include <libutil.h> + +int +openpty(amaster, aslave, name, termp, winp) + int *amaster, *aslave; + char *name; + struct termios *termp; + struct winsize *winp; +{ + char line[] = "/dev/ptyXX"; + const char *cp1, *cp2; + int master, slave, ttygid; + struct group *gr; + + if ((gr = getgrnam("tty")) != NULL) + ttygid = gr->gr_gid; + else + ttygid = -1; + + 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) + break; /* try the next pty group */ + } 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 */ + return (-1); +} + +int +forkpty(amaster, name, termp, winp) + int *amaster; + char *name; + struct termios *termp; + struct winsize *winp; +{ + int master, slave, pid; + + if (openpty(&master, &slave, name, termp, winp) == -1) + return (-1); + switch (pid = fork()) { + case -1: + return (-1); + case 0: + /* + * child + */ + (void) close(master); + login_tty(slave); + return (0); + } + /* + * parent + */ + *amaster = master; + (void) close(slave); + return (pid); +} diff --git a/lib/libutil/pw_util.c b/lib/libutil/pw_util.c new file mode 100644 index 0000000..2c082e4 --- /dev/null +++ b/lib/libutil/pw_util.c @@ -0,0 +1,264 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static const char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94"; +#endif +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +/* + * This file is used by all the "password" programs; vipw(8), chpass(1), + * and passwd(1). + */ + +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include <err.h> +#include <fcntl.h> +#include <paths.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "pw_util.h" + +extern char *tempname; +static pid_t editpid = -1; +static int lockfd; +static char _default_editor[] = _PATH_VI; +char mppath[] = _PATH_PWD; +char masterpasswd[] = _PATH_MASTERPASSWD; + +void pw_cont(int); + +void +pw_cont(int sig) +{ + + if (editpid != -1) + kill(editpid, sig); +} + +void +pw_init(void) +{ + struct rlimit rlim; + + /* Unlimited resource limits. */ + rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; + (void)setrlimit(RLIMIT_CPU, &rlim); + (void)setrlimit(RLIMIT_FSIZE, &rlim); + (void)setrlimit(RLIMIT_STACK, &rlim); + (void)setrlimit(RLIMIT_DATA, &rlim); + (void)setrlimit(RLIMIT_RSS, &rlim); + + /* Don't drop core (not really necessary, but GP's). */ + rlim.rlim_cur = rlim.rlim_max = 0; + (void)setrlimit(RLIMIT_CORE, &rlim); + + /* Turn off signals. */ + (void)signal(SIGALRM, SIG_IGN); + (void)signal(SIGHUP, SIG_IGN); + (void)signal(SIGINT, SIG_IGN); + (void)signal(SIGPIPE, SIG_IGN); + (void)signal(SIGQUIT, SIG_IGN); + (void)signal(SIGTERM, SIG_IGN); + (void)signal(SIGCONT, pw_cont); + + /* Create with exact permissions. */ + (void)umask(0); +} + +int +pw_lock(void) +{ + /* + * If the master password file doesn't exist, the system is hosed. + * Might as well try to build one. Set the close-on-exec bit so + * that users can't get at the encrypted passwords while editing. + * Open should allow flock'ing the file; see 4.4BSD. XXX + */ + for (;;) { + struct stat st; + + lockfd = open(masterpasswd, O_RDONLY, 0); + if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) + err(1, "%s", masterpasswd); + if (flock(lockfd, LOCK_EX|LOCK_NB)) + errx(1, "the password db file is busy"); + + /* + * If the password file was replaced while we were trying to + * get the lock, our hardlink count will be 0 and we have to + * close and retry. + */ + if (fstat(lockfd, &st) < 0) + errx(1, "fstat() failed"); + if (st.st_nlink != 0) + break; + close(lockfd); + lockfd = -1; + } + return (lockfd); +} + +int +pw_tmp(void) +{ + static char path[MAXPATHLEN]; + int fd; + char *p; + + strncpy(path, masterpasswd, MAXPATHLEN - 1); + path[MAXPATHLEN] = '\0'; + + if ((p = strrchr(path, '/'))) + ++p; + else + p = path; + strcpy(p, "pw.XXXXXX"); + if ((fd = mkstemp(path)) == -1) + err(1, "%s", path); + tempname = path; + return (fd); +} + +int +pw_mkdb(const char *username) +{ + int pstat; + pid_t pid; + + (void)fflush(stderr); + if (!(pid = fork())) { + if(!username) { + warnx("rebuilding the database..."); + execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath, + tempname, (char *)NULL); + } else { + warnx("updating the database..."); + execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath, + "-u", username, tempname, (char *)NULL); + } + pw_error(_PATH_PWD_MKDB, 1, 1); + } + pid = waitpid(pid, &pstat, 0); + if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0) + return (0); + warnx("done"); + return (1); +} + +void +pw_edit(int notsetuid) +{ + int pstat; + char *p, *editor; + + if (!(editor = getenv("EDITOR"))) + editor = _default_editor; + if ((p = strrchr(editor, '/'))) + ++p; + else + p = editor; + + if (!(editpid = fork())) { + if (notsetuid) { + (void)setgid(getgid()); + (void)setuid(getuid()); + } + errno = 0; + execlp(editor, p, tempname, (char *)NULL); + _exit(errno); + } + for (;;) { + editpid = waitpid(editpid, (int *)&pstat, WUNTRACED); + errno = WEXITSTATUS(pstat); + if (editpid == -1) + pw_error(editor, 1, 1); + else if (WIFSTOPPED(pstat)) + raise(WSTOPSIG(pstat)); + else if (WIFEXITED(pstat) && errno == 0) + break; + else + pw_error(editor, 1, 1); + } + editpid = -1; +} + +void +pw_prompt(void) +{ + int c, first; + + (void)printf("re-edit the password file? [y]: "); + (void)fflush(stdout); + first = c = getchar(); + while (c != '\n' && c != EOF) + c = getchar(); + if (first == 'n') + pw_error(NULL, 0, 0); +} + +void +pw_error(const char *name, int error, int eval) +{ +#ifdef YP + extern int _use_yp; +#endif /* YP */ + if (error) { + if (name != NULL) + warn("%s", name); + else + warn(NULL); + } +#ifdef YP + if (_use_yp) + warnx("NIS information unchanged"); + else +#endif /* YP */ + warnx("%s: unchanged", masterpasswd); + (void)unlink(tempname); + exit(eval); +} diff --git a/lib/libutil/realhostname.3 b/lib/libutil/realhostname.3 new file mode 100644 index 0000000..1b4ae3d --- /dev/null +++ b/lib/libutil/realhostname.3 @@ -0,0 +1,103 @@ +.\" Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd April 6, 1999 +.Os +.Dt REALHOSTNAME 3 +.Sh NAME +.Nm realhostname +.Nd "convert an IP number to the real host name" +.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" +.Sh DESCRIPTION +The function +.Fn realhostname +converts +.Ar ip +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 +.Ar ip . +.Pp +.Ar host +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 +than +.Ar hsize +bytes, +.Xr inet_ntoa 3 +is used to convert +.Ar ip +to an ASCII form. +.Pp +If the string written to +.Ar host +is +.Ar hsize +bytes long, +.Ar host +will not be NUL terminated. +.Sh RETURN VALUES +.Fn realhostname +will return one of the following constants which are defined in +.Pa libutil.h : +.Pp +.Bl -tag -width XXX -offset XXX +.It Li HOSTNAME_FOUND +A valid host name was found. +.It Li HOSTNAME_INCORRECTNAME +A host name was found, but it did not resolve back to the passed +.Ar ip . +.Ar host +now contains the numeric value of +.Ar ip . +.It Li HOSTNAME_INVALIDADDR +.Ar ip +could not be resolved. +.Ar host +now contains the numeric value of +.Ar ip . +.It Li HOSTNAME_INVALIDNAME +A host name was found, but it could not be resolved back to any ip number. +.Ar host +now contains the numeric value of +.Ar ip . +.El +.Sh SEE ALSO +.Xr gethostbyaddr 3 , +.Xr gethostbyname 3 , +.Xr inet_ntoa 3 , +.Xr realhostname_sa 3 diff --git a/lib/libutil/realhostname.c b/lib/libutil/realhostname.c new file mode 100644 index 0000000..9c033e9 --- /dev/null +++ b/lib/libutil/realhostname.c @@ -0,0 +1,191 @@ +/*- + * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> + +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <stdio.h> +#include <string.h> + +#include "libutil.h" + +/* wrapper for KAME-special getnameinfo() */ +#ifndef NI_WITHSCOPEID +#define NI_WITHSCOPEID 0 +#endif + +struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; +}; + +int +realhostname(char *host, size_t hsize, const struct in_addr *ip) +{ + char trimmed[MAXHOSTNAMELEN]; + int result; + struct hostent *hp; + + result = HOSTNAME_INVALIDADDR; + hp = gethostbyaddr((char *)ip, sizeof(*ip), AF_INET); + + if (hp != NULL) { + strlcpy(trimmed, hp->h_name, sizeof(trimmed)); + trimdomain(trimmed, strlen(trimmed)); + if (strlen(trimmed) <= hsize) { + char lookup[MAXHOSTNAMELEN]; + + strncpy(lookup, hp->h_name, sizeof(lookup) - 1); + lookup[sizeof(lookup) - 1] = '\0'; + hp = gethostbyname(lookup); + if (hp == NULL) + result = HOSTNAME_INVALIDNAME; + else for (; ; hp->h_addr_list++) { + if (*hp->h_addr_list == NULL) { + result = HOSTNAME_INCORRECTNAME; + break; + } + if (!memcmp(*hp->h_addr_list, ip, sizeof(*ip))) { + strncpy(host, trimmed, hsize); + return HOSTNAME_FOUND; + } + } + } + } + + strncpy(host, inet_ntoa(*ip), hsize); + + return result; +} + +int +realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, int addrlen) +{ + int result, error; + char buf[NI_MAXHOST]; + struct sockaddr_in sin; + + result = HOSTNAME_INVALIDADDR; + +#ifdef INET6 + /* 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)) { + struct sockaddr_in6 *sin6; + + sin6 = (struct 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], + sizeof(struct in_addr)); + addr = (struct sockaddr *)&sin; + addrlen = sin.sin_len; + } +#endif + + error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, + NI_WITHSCOPEID); + if (error == 0) { + struct addrinfo hints, *res, *ores; + struct sockaddr *sa; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = addr->sa_family; + hints.ai_flags = AI_CANONNAME | AI_PASSIVE; + hints.ai_socktype = SOCK_STREAM; + + error = getaddrinfo(buf, NULL, &hints, &res); + if (error) { + result = HOSTNAME_INVALIDNAME; + goto numeric; + } + for (ores = res; ; res = res->ai_next) { + if (res == NULL) { + freeaddrinfo(ores); + result = HOSTNAME_INCORRECTNAME; + goto numeric; + } + sa = res->ai_addr; + if (sa == NULL) { + freeaddrinfo(ores); + result = HOSTNAME_INCORRECTNAME; + goto numeric; + } + if (sa->sa_len == addrlen && + sa->sa_family == addr->sa_family) { + ((struct sockinet *)sa)->si_port = ((struct 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; +#endif + if (!memcmp(sa, addr, sa->sa_len)) { + result = HOSTNAME_FOUND; + if (ores->ai_canonname == NULL) { + freeaddrinfo(ores); + goto numeric; + } + strlcpy(buf, ores->ai_canonname, + sizeof(buf)); + trimdomain(buf, hsize); + if (strlen(buf) > hsize && + addr->sa_family == AF_INET) { + freeaddrinfo(ores); + goto numeric; + } + strncpy(host, buf, hsize); + break; + } + } + } + freeaddrinfo(ores); + } else { + numeric: + if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, + NI_NUMERICHOST|NI_WITHSCOPEID) == 0) + strncpy(host, buf, hsize); + } + + return result; +} + + diff --git a/lib/libutil/realhostname_sa.3 b/lib/libutil/realhostname_sa.3 new file mode 100644 index 0000000..e07720d --- /dev/null +++ b/lib/libutil/realhostname_sa.3 @@ -0,0 +1,129 @@ +.\" Copyright (C) 1995, 1996, 1997, 1998, 1999, and 2000 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project 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 PROJECT 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 PROJECT 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. +.\" +.\" Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd January 11, 2000 +.Os +.Dt REALHOSTNAME_SA 3 +.Sh NAME +.Nm realhostname_sa +.Nd "convert an struct sockaddr to the real host name" +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In netinet/in.h +.In libutil.h +.Ft int +.Fn realhostname_sa "char *host" "size_t hsize" "struct sockaddr *addr" "int addrlen" +.Sh DESCRIPTION +The function +.Fn realhostname_sa +converts +.Ar addr +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 +.Ar addr . +.Pp +.Ar host +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 +than +.Ar hsize +bytes, +.Xr getnameinfo 3 +with NI_NUMERICHOST specified, is used to convert +.Ar addr +to an ASCII form. +.Pp +If the string written to +.Ar host +is +.Ar hsize +bytes long, +.Ar host +will not be NUL terminated. +.Sh RETURN VALUES +.Fn realhostname_sa +will return one of the following constants which are defined in +.Pa libutil.h : +.Pp +.Bl -tag -width XXX -offset XXX +.It Li HOSTNAME_FOUND +A valid host name was found. +.It Li HOSTNAME_INCORRECTNAME +A host name was found, but it did not resolve back to the passed +.Ar ip . +.Ar host +now contains the numeric value of +.Ar ip . +.It Li HOSTNAME_INVALIDADDR +.Ar ip +could not be resolved. +.Ar host +now contains the numeric value of +.Ar ip . +.It Li HOSTNAME_INVALIDNAME +A host name was found, but it could not be resolved back to any ip number. +.Ar host +now contains the numeric value of +.Ar ip . +.El +.Sh SEE ALSO +.Xr getaddrinfo 3 , +.Xr getnameinfo 3 , +.Xr realhostname 3 diff --git a/lib/libutil/stub.c b/lib/libutil/stub.c new file mode 100644 index 0000000..ef19276 --- /dev/null +++ b/lib/libutil/stub.c @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2000 Brian Fundakowski Feldman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdio.h> +#include <stdlib.h> + +/* + * Stub out what's in -lcrypt. + */ + +#pragma weak crypt_set_format +int +crypt_set_format(const char *f) { + + if (getenv("CRYPT_DEBUG") != NULL) + fprintf(stderr, "crypt_set_format: eek, stub called!\n"); + return (0); +} diff --git a/lib/libutil/trimdomain.3 b/lib/libutil/trimdomain.3 new file mode 100644 index 0000000..2b6dd75 --- /dev/null +++ b/lib/libutil/trimdomain.3 @@ -0,0 +1,81 @@ +.\" Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd April 7, 1999 +.Os +.Dt TRIMDOMAIN 3 +.Sh NAME +.Nm trimdomain +.Nd "trim the current domain name from a host name" +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In libutil.h +.Ft void +.Fn trimdomain "char *fullhost" "int hostsize" +.Sh DESCRIPTION +The function +.Fn trimdomain +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 +name is determined by calling +.Xr gethostname 3 +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 +.Fn trimdomain +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 +.Ar hostsize . +.Pp +If the passed +.Ar fullname +is actually a +.Dv DISPLAY +specification of the form +.Sm off +.Ar host . domain : nn Oo . +.Ar nn +.Oc +.Sm on +and the domain name is the same as the local domain name, +.Fn trimdomain +will remove the embedded domain name, copying the screen and display +numbers to the end of the base host name and resulting in +.Sm off +.Ar host : nn Op . Ar nn . +.Sm on +.Sh RETURN VALUES +.Fn trimdomain +does not return a value. +.Sh SEE ALSO +.Xr gethostname 3 diff --git a/lib/libutil/trimdomain.c b/lib/libutil/trimdomain.c new file mode 100644 index 0000000..a2cdf19 --- /dev/null +++ b/lib/libutil/trimdomain.c @@ -0,0 +1,116 @@ +/*- + * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org> + * Based on original work by Atsushi Murai <amurai@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> + +#include <libutil.h> +#include <string.h> +#include <unistd.h> + +static int isDISP(const char *); + +/*- + * Trim the current domain name from fullhost, but only if the result + * is less than or equal to hostsize in length. + * + * This function understands $DISPLAY type fullhosts. + * + * For example: + * + * trimdomain("abcde.my.domain", 5) -> "abcde" + * trimdomain("abcde.my.domain", 4) -> "abcde.my.domain" + * trimdomain("abcde.my.domain:0.0", 9) -> "abcde:0.0" + * trimdomain("abcde.my.domain:0.0", 8) -> "abcde.my.domain:0.0" + */ +void +trimdomain(char *fullhost, int hostsize) +{ + static size_t dlen; + static int first = 1; + static char domain[MAXHOSTNAMELEN]; + char *end, *s; + size_t len; + + if (first) { + /* XXX: Should we assume that our domain is this persistent ? */ + first = 0; + if (gethostname(domain, sizeof(domain) - 1) == 0 && + (s = strchr(domain, '.')) != NULL) + memmove(domain, s + 1, strlen(s + 1) + 1); + else + domain[0] = '\0'; + dlen = strlen(domain); + } + + if (domain[0] == '\0') + return; + + s = fullhost; + end = s + hostsize + 1; + for (; (s = memchr(s, '.', end - s)) != NULL; s++) { + 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)) < end - s) { + /* Found -- shuffle the DISPLAY back. */ + memmove(s, s + dlen + 1, len + 1); + break; + } + } + } +} + +/* + * Is the given string NN or NN.NN where ``NN'' is an all-numeric string ? + */ +static int +isDISP(const char *disp) +{ + int res, w; + + w = strspn(disp, "0123456789"); + res = 0; + if (w > 0) { + if (disp[w] == '\0') + res = 1; /* NN */ + else if (disp[w] == '.') { + disp += w + 1; + w = strspn(disp, "0123456789"); + if (w > 0 && disp[w] == '\0') + res = 1; /* NN.NN */ + } + } + return (res); +} diff --git a/lib/libutil/uucplock.3 b/lib/libutil/uucplock.3 new file mode 100644 index 0000000..a69af95 --- /dev/null +++ b/lib/libutil/uucplock.3 @@ -0,0 +1,179 @@ +.\" +.\" Copyright (c) 1996 Brian Somers <brian@awfulhak.demon.co.uk> +.\" +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" " +.Dd March 30, 1997 +.Os +.Dt UUCPLOCK 3 +.Sh NAME +.Nm uu_lock , +.Nm uu_unlock , +.Nm uu_lockerr +.Nd acquire and release control of a serial device +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In libutil.h +.Ft int +.Fn uu_lock "const char *ttyname" +.Ft int +.Fn uu_lock_txfr "const char *ttyname" "pid_t pid" +.Ft int +.Fn uu_unlock "const char *ttyname" +.Ft const char * +.Fn uu_lockerr "int uu_lockresult" +.Sh DESCRIPTION +The +.Fn uu_lock +function attempts to create a lock file called +.Pa /var/spool/lock/LCK.. +with a suffix given by the passed +.Fa ttyname . +If the file already exists, it is expected to contain the process +id of the locking program. +.Pp +If the file does not already exist, or the owning process given by +the process id found in the lock file is no longer running, +.Fn uu_lock +will write its own process id into the file and return success. +.Pp +.Fn uu_lock_txfr +transfers lock ownership to another process. +.Fn uu_lock +must have previously been successful. +.Pp +.Fn uu_unlock +removes the lockfile created by +.Fn uu_lock +for the given +.Fa ttyname . +Care should be taken that +.Fn uu_lock +was successful before calling +.Fn uu_unlock . +.Pp +.Fn uu_lockerr +returns an error string representing the error +.Fa uu_lockresult , +as returned from +.Fn uu_lock . +.Sh RETURN VALUES +.Fn uu_unlock +returns 0 on success and -1 on failure. +.Pp +.Fn uu_lock +may return any of the following values: +.Pp +.Dv UU_LOCK_INUSE : +The lock is in use by another process. +.Pp +.Dv UU_LOCK_OK : +The lock was successfully created. +.Pp +.Dv UU_LOCK_OPEN_ERR : +The lock file could not be opened via +.Xr open 2 . +.Pp +.Dv UU_LOCK_READ_ERR : +The lock file could not be read via +.Xr read 2 . +.Pp +.Dv UU_LOCK_CREAT_ERR : +Can't create temporary lock file via +.Xr creat 2 . +.Pp +.Dv UU_LOCK_WRITE_ERR : +The current process id could not be written to the lock file via a call to +.Xr write 2 . +.Pp +.Dv UU_LOCK_LINK_ERR : +Can't link temporary lock file via +.Xr link 2 . +.Pp +.Dv UU_LOCK_TRY_ERR : +Locking attempts are failed after 5 tries. +.Pp +If a value of +.Dv UU_LOCK_OK +is passed to +.Fn uu_lockerr , +an empty string is returned. +Otherwise, a string specifying +the reason for failure is returned. +.Fn uu_lockerr +uses the current value of +.Va errno +to determine the exact error. Care should be made not to allow +.Va errno +to be changed between calls to +.Fn uu_lock +and +.Fn uu_lockerr . +.Pp +.Fn uu_lock_txfr +may return any of the following values: +.Pp +.Dv UU_LOCK_OK : +The transfer was successful. The specified process now holds the device +lock. +.Pp +.Dv UU_LOCK_OWNER_ERR : +The current process does not already own a lock on the specified device. +.Pp +.Dv UU_LOCK_WRITE_ERR : +The new process id could not be written to the lock file via a call to +.Xr write 2 . +.Sh ERRORS +If +.Fn uu_lock +returns one of the error values above, the global value +.Va errno +can be used to determine the cause. Refer to the respective manual pages +for further details. +.Pp +.Fn uu_unlock +will set the global variable +.Va errno +to reflect the reason that the lock file could not be removed. +Refer to the description of +.Xr unlink 2 +for further details. +.Sh SEE ALSO +.Xr lseek 2 , +.Xr open 2 , +.Xr read 2 , +.Xr write 2 +.Sh BUGS +It is possible that a stale lock is not recognised as such if a new +processes is assigned the same processes id as the program that left +the stale lock. +.Pp +The calling process must have write permissions to the +.Pa /var/spool/lock +directory. There is no mechanism in place to ensure that the +permissions of this directory are the same as those of the +serial devices that might be locked. diff --git a/lib/libutil/uucplock.c b/lib/libutil/uucplock.c new file mode 100644 index 0000000..6b2e2c5 --- /dev/null +++ b/lib/libutil/uucplock.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifndef lint +static const char sccsid[] = "@(#)uucplock.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/file.h> +#include <dirent.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <paths.h> +#include <string.h> +#include "libutil.h" + +#define MAXTRIES 5 + +#define LOCKTMP "LCKTMP..%d" +#define LOCKFMT "LCK..%s" + +#define GORET(level, val) { err = errno; uuerr = (val); \ + goto __CONCAT(ret, level); } + +/* Forward declarations */ +static int put_pid (int fd, pid_t pid); +static pid_t get_pid (int fd,int *err); + +/* + * uucp style locking routines + */ + +int +uu_lock(const char *ttyname) +{ + int fd, tmpfd, i; + pid_t pid, pid_old; + char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN], + lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; + int err, uuerr; + + pid = getpid(); + (void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP, + pid); + (void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, + ttyname); + if ((tmpfd = creat(lcktmpname, 0664)) < 0) + GORET(0, UU_LOCK_CREAT_ERR); + + for (i = 0; i < MAXTRIES; i++) { + if (link (lcktmpname, lckname) < 0) { + if (errno != EEXIST) + GORET(1, UU_LOCK_LINK_ERR); + /* + * file is already locked + * check to see if the process holding the lock + * still exists + */ + if ((fd = open(lckname, O_RDONLY)) < 0) + GORET(1, UU_LOCK_OPEN_ERR); + + if ((pid_old = get_pid (fd, &err)) == -1) + GORET(2, UU_LOCK_READ_ERR); + + close(fd); + + if (kill(pid_old, 0) == 0 || errno != ESRCH) + GORET(1, UU_LOCK_INUSE); + /* + * The process that locked the file isn't running, so + * we'll lock it ourselves + */ + (void)unlink(lckname); + } else { + if (!put_pid (tmpfd, pid)) + GORET(3, UU_LOCK_WRITE_ERR); + break; + } + } + GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK); + +ret3: + (void)unlink(lckname); + goto ret1; +ret2: + (void)close(fd); +ret1: + (void)close(tmpfd); + (void)unlink(lcktmpname); +ret0: + errno = err; + return uuerr; +} + +int +uu_lock_txfr(const char *ttyname, pid_t pid) +{ + int fd, err; + char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; + + snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, ttyname); + + if ((fd = open(lckname, O_RDWR)) < 0) + return UU_LOCK_OWNER_ERR; + if (get_pid(fd, &err) != getpid()) + err = UU_LOCK_OWNER_ERR; + else { + lseek(fd, 0, SEEK_SET); + err = put_pid(fd, pid) ? 0 : UU_LOCK_WRITE_ERR; + } + close(fd); + + return err; +} + +int +uu_unlock(const char *ttyname) +{ + char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; + + (void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, ttyname); + return unlink(tbuf); +} + +const char * +uu_lockerr(int uu_lockresult) +{ + static char errbuf[128]; + char *fmt; + + switch (uu_lockresult) { + case UU_LOCK_INUSE: + return "device in use"; + case UU_LOCK_OK: + return ""; + case UU_LOCK_OPEN_ERR: + fmt = "open error: %s"; + break; + case UU_LOCK_READ_ERR: + fmt = "read error: %s"; + break; + case UU_LOCK_CREAT_ERR: + fmt = "creat error: %s"; + break; + case UU_LOCK_WRITE_ERR: + fmt = "write error: %s"; + break; + case UU_LOCK_LINK_ERR: + fmt = "link error: %s"; + break; + case UU_LOCK_TRY_ERR: + fmt = "too many tries: %s"; + break; + case UU_LOCK_OWNER_ERR: + fmt = "not locking process: %s"; + break; + default: + fmt = "undefined error: %s"; + break; + } + + (void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno)); + return errbuf; +} + +static int +put_pid(int fd, pid_t pid) +{ + char buf[32]; + int len; + + len = sprintf (buf, "%10d\n", (int)pid); + return write (fd, buf, len) == len; +} + +static pid_t +get_pid(int fd, int *err) +{ + int bytes_read; + char buf[32]; + pid_t pid; + + bytes_read = read (fd, buf, sizeof (buf) - 1); + if (bytes_read > 0) { + buf[bytes_read] = '\0'; + pid = strtol (buf, (char **) NULL, 10); + } else { + pid = -1; + *err = bytes_read ? errno : EINVAL; + } + return pid; +} + +/* end of uucplock.c */ |