diff options
author | Marcel Moolenaar <marcel@FreeBSD.org> | 2010-03-10 02:16:04 +0000 |
---|---|---|
committer | Marcel Moolenaar <marcel@FreeBSD.org> | 2010-03-10 02:16:04 +0000 |
commit | 50568f27d680f3a286fdcfaebb5e4f361c4c7e8b (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /libutil | |
parent | d14d0b2c1107f8cf2cb372a38f82146fca1a9a2a (diff) | |
download | pw-darwin-50568f27d680f3a286fdcfaebb5e4f361c4c7e8b.tar.gz pw-darwin-50568f27d680f3a286fdcfaebb5e4f361c4c7e8b.tar.zst pw-darwin-50568f27d680f3a286fdcfaebb5e4f361c4c7e8b.zip |
Create the altix project branch. The altix project will add support
for the SGI Altix 350 to FreeBSD/ia64. The hardware used for porting
is a two-module system, consisting of a base compute module and a
CPU expansion module. SGI's NUMAFlex architecture can be an excellent
platform to test CPU affinity and NUMA-aware features in FreeBSD.
Diffstat (limited to 'libutil')
-rw-r--r-- | libutil/_secure_path.c | 74 | ||||
-rw-r--r-- | libutil/flopen.c | 105 | ||||
-rw-r--r-- | libutil/gr_util.c | 250 | ||||
-rw-r--r-- | libutil/libutil.h | 212 | ||||
-rw-r--r-- | libutil/login_cap.c | 819 | ||||
-rw-r--r-- | libutil/login_cap.h | 166 | ||||
-rw-r--r-- | libutil/login_crypt.c | 50 | ||||
-rw-r--r-- | libutil/pw_util.c | 621 |
8 files changed, 0 insertions, 2297 deletions
diff --git a/libutil/_secure_path.c b/libutil/_secure_path.c deleted file mode 100644 index 363378b..0000000 --- a/libutil/_secure_path.c +++ /dev/null @@ -1,74 +0,0 @@ -/*- - * 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 writable only by root (or given owner) - * 3. Group ownership is given group or is non-group writable - * - * Returns: -2 if file does not exist, - * -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 ((int)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 ((int)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/libutil/flopen.c b/libutil/flopen.c deleted file mode 100644 index 754c9c0..0000000 --- a/libutil/flopen.c +++ /dev/null @@ -1,105 +0,0 @@ -/*- - * Copyright (c) 2007 Dag-Erling Coïdan Smørgrav - * 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 - * in this position and unchanged. - * 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/file.h> -#include <sys/stat.h> - -#include <errno.h> -#include <stdarg.h> -#include <unistd.h> - -#include <libutil.h> - -int -flopen(const char *path, int flags, ...) -{ - int fd, operation, serrno, trunc; - struct stat sb, fsb; - mode_t mode; - -#ifdef O_EXLOCK - flags &= ~O_EXLOCK; -#endif - - mode = 0; - if (flags & O_CREAT) { - va_list ap; - - va_start(ap, flags); - mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */ - va_end(ap); - } - - operation = LOCK_EX; - if (flags & O_NONBLOCK) - operation |= LOCK_NB; - - trunc = (flags & O_TRUNC); - flags &= ~O_TRUNC; - - for (;;) { - if ((fd = open(path, flags, mode)) == -1) - /* non-existent or no access */ - return (-1); - if (flock(fd, operation) == -1) { - /* unsupported or interrupted */ - serrno = errno; - (void)close(fd); - errno = serrno; - return (-1); - } - if (stat(path, &sb) == -1) { - /* disappeared from under our feet */ - (void)close(fd); - continue; - } - if (fstat(fd, &fsb) == -1) { - /* can't happen [tm] */ - serrno = errno; - (void)close(fd); - errno = serrno; - return (-1); - } - if (sb.st_dev != fsb.st_dev || - sb.st_ino != fsb.st_ino) { - /* changed under our feet */ - (void)close(fd); - continue; - } - if (trunc && ftruncate(fd, 0) != 0) { - /* can't happen [tm] */ - serrno = errno; - (void)close(fd); - errno = serrno; - return (-1); - } - return (fd); - } -} diff --git a/libutil/gr_util.c b/libutil/gr_util.c deleted file mode 100644 index 633f435..0000000 --- a/libutil/gr_util.c +++ /dev/null @@ -1,250 +0,0 @@ -/*- - * Copyright (c) 2008 Sean C. Farley <scf@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, - * without modification, immediately at the beginning of 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 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 <grp.h> -#include <inttypes.h> -#include <libutil.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -struct group_storage { - struct group gr; - char *members[]; -}; - -static const char group_line_format[] = "%s:%s:%ju:"; - -/* - * Compares two struct group's. - */ -int -gr_equal(const struct group *gr1, const struct group *gr2) -{ - int gr1_ndx; - int gr2_ndx; - bool found; - - /* Check that the non-member information is the same. */ - if (gr1->gr_name == NULL || gr2->gr_name == NULL) { - if (gr1->gr_name != gr2->gr_name) - return (false); - } else if (strcmp(gr1->gr_name, gr2->gr_name) != 0) - return (false); - if (gr1->gr_passwd == NULL || gr2->gr_passwd == NULL) { - if (gr1->gr_passwd != gr2->gr_passwd) - return (false); - } else if (strcmp(gr1->gr_passwd, gr2->gr_passwd) != 0) - return (false); - if (gr1->gr_gid != gr2->gr_gid) - return (false); - - /* Check all members in both groups. */ - if (gr1->gr_mem == NULL || gr2->gr_mem == NULL) { - if (gr1->gr_mem != gr2->gr_mem) - return (false); - } else { - for (found = false, gr1_ndx = 0; gr1->gr_mem[gr1_ndx] != NULL; - gr1_ndx++) { - for (gr2_ndx = 0; gr2->gr_mem[gr2_ndx] != NULL; - gr2_ndx++) - if (strcmp(gr1->gr_mem[gr1_ndx], - gr2->gr_mem[gr2_ndx]) == 0) { - found = true; - break; - } - if (!found) - return (false); - } - - /* Check that group2 does not have more members than group1. */ - if (gr2->gr_mem[gr1_ndx] != NULL) - return (false); - } - - return (true); -} - -/* - * Make a group line out of a struct group. - */ -char * -gr_make(const struct group *gr) -{ - char *line; - size_t line_size; - int ndx; - - /* Calculate the length of the group line. */ - line_size = snprintf(NULL, 0, group_line_format, gr->gr_name, - gr->gr_passwd, (uintmax_t)gr->gr_gid) + 1; - if (gr->gr_mem != NULL) { - for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) - line_size += strlen(gr->gr_mem[ndx]) + 1; - if (ndx > 0) - line_size--; - } - - /* Create the group line and fill it. */ - if ((line = malloc(line_size)) == NULL) - return (NULL); - snprintf(line, line_size, group_line_format, gr->gr_name, gr->gr_passwd, - (uintmax_t)gr->gr_gid); - if (gr->gr_mem != NULL) - for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) { - strcat(line, gr->gr_mem[ndx]); - if (gr->gr_mem[ndx + 1] != NULL) - strcat(line, ","); - } - - return (line); -} - -/* - * Duplicate a struct group. - */ -struct group * -gr_dup(const struct group *gr) -{ - char *dst; - size_t len; - struct group_storage *gs; - int ndx; - int num_mem; - - /* Calculate size of the group. */ - len = sizeof(*gs); - if (gr->gr_name != NULL) - len += strlen(gr->gr_name) + 1; - if (gr->gr_passwd != NULL) - len += strlen(gr->gr_passwd) + 1; - if (gr->gr_mem != NULL) { - for (num_mem = 0; gr->gr_mem[num_mem] != NULL; num_mem++) - len += strlen(gr->gr_mem[num_mem]) + 1; - len += (num_mem + 1) * sizeof(*gr->gr_mem); - } else - num_mem = -1; - - /* Create new group and copy old group into it. */ - if ((gs = calloc(1, len)) == NULL) - return (NULL); - dst = (char *)&gs->members[num_mem + 1]; - if (gr->gr_name != NULL) { - gs->gr.gr_name = dst; - dst = stpcpy(gs->gr.gr_name, gr->gr_name) + 1; - } - if (gr->gr_passwd != NULL) { - gs->gr.gr_passwd = dst; - dst = stpcpy(gs->gr.gr_passwd, gr->gr_passwd) + 1; - } - gs->gr.gr_gid = gr->gr_gid; - if (gr->gr_mem != NULL) { - gs->gr.gr_mem = gs->members; - for (ndx = 0; ndx < num_mem; ndx++) { - gs->gr.gr_mem[ndx] = dst; - dst = stpcpy(gs->gr.gr_mem[ndx], gr->gr_mem[ndx]) + 1; - } - gs->gr.gr_mem[ndx] = NULL; - } - - return (&gs->gr); -} - -/* - * Scan a line and place it into a group structure. - */ -static bool -__gr_scan(char *line, struct group *gr) -{ - char *loc; - int ndx; - - /* Assign non-member information to structure. */ - gr->gr_name = line; - if ((loc = strchr(line, ':')) == NULL) - return (false); - *loc = '\0'; - gr->gr_passwd = loc + 1; - if (*gr->gr_passwd == ':') - *gr->gr_passwd = '\0'; - else { - if ((loc = strchr(loc + 1, ':')) == NULL) - return (false); - *loc = '\0'; - } - if (sscanf(loc + 1, "%u", &gr->gr_gid) != 1) - return (false); - - /* Assign member information to structure. */ - if ((loc = strchr(loc + 1, ':')) == NULL) - return (false); - line = loc + 1; - gr->gr_mem = NULL; - ndx = 0; - do { - gr->gr_mem = reallocf(gr->gr_mem, sizeof(*gr->gr_mem) * - (ndx + 1)); - if (gr->gr_mem == NULL) - return (false); - - /* Skip locations without members (i.e., empty string). */ - do { - gr->gr_mem[ndx] = strsep(&line, ","); - } while (gr->gr_mem[ndx] != NULL && *gr->gr_mem[ndx] == '\0'); - } while (gr->gr_mem[ndx++] != NULL); - - return (true); -} - -/* - * Create a struct group from a line. - */ -struct group * -gr_scan(const char *line) -{ - struct group gr; - char *line_copy; - struct group *new_gr; - - if ((line_copy = strdup(line)) == NULL) - return (NULL); - if (!__gr_scan(line_copy, &gr)) { - free(line_copy); - return (NULL); - } - new_gr = gr_dup(&gr); - free(line_copy); - if (gr.gr_mem != NULL) - free(gr.gr_mem); - - return (new_gr); -} diff --git a/libutil/libutil.h b/libutil/libutil.h deleted file mode 100644 index 4c2ee3b..0000000 --- a/libutil/libutil.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 1996 Peter Wemm <peter@FreeBSD.org>. - * All rights reserved. - * Copyright (c) 2002 Networks Associates Technology, Inc. - * All rights reserved. - * - * Portions of this software were developed for the FreeBSD Project by - * ThinkSec AS and NAI Labs, the Security Research Division of Network - * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 - * ("CBOSS"), as part of the DARPA CHATS research program. - * - * 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. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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> -#include <sys/_types.h> - -#ifndef _GID_T_DECLARED -typedef __gid_t gid_t; -#define _GID_T_DECLARED -#endif - -#ifndef _INT64_T_DECLARED -typedef __int64_t int64_t; -#define _INT64_T_DECLARED -#endif - -#ifndef _PID_T_DECLARED -typedef __pid_t pid_t; -#define _PID_T_DECLARED -#endif - -#ifndef _SIZE_T_DECLARED -typedef __size_t size_t; -#define _SIZE_T_DECLARED -#endif - -#ifndef _UID_T_DECLARED -typedef __uid_t uid_t; -#define _UID_T_DECLARED -#endif - -#define PROPERTY_MAX_NAME 64 -#define PROPERTY_MAX_VALUE 512 - -/* for properties.c */ -typedef struct _property { - struct _property *next; - char *name; - char *value; -} *properties; - -#ifdef _SYS_PARAM_H_ -/* for pidfile.c */ -struct pidfh { - int pf_fd; - char pf_path[MAXPATHLEN + 1]; - __dev_t pf_dev; - ino_t pf_ino; -}; -#endif - -/* Avoid pulling in all the include files for no need */ -struct termios; -struct winsize; -struct in_addr; -struct kinfo_file; -struct kinfo_vmentry; - -__BEGIN_DECLS -void clean_environment(const char * const *_white, - const char * const *_more_white); -int extattr_namespace_to_string(int _attrnamespace, char **_string); -int extattr_string_to_namespace(const char *_string, int *_attrnamespace); -int flopen(const char *_path, int _flags, ...); -void hexdump(const void *ptr, int length, const char *hdr, int flags); -int login_tty(int _fd); -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); -int humanize_number(char *_buf, size_t _len, int64_t _number, - const char *_suffix, int _scale, int _flags); -int expand_number(const char *_buf, int64_t *_num); -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); - -int kld_isloaded(const char *name); -int kld_load(const char *name); -struct kinfo_file * - kinfo_getfile(pid_t _pid, int *_cntp); -struct kinfo_vmentry * - kinfo_getvmmap(pid_t _pid, int *_cntp); - -#ifdef _STDIO_H_ /* avoid adding new includes */ -char *fparseln(FILE *, size_t *, size_t *, const char[3], int); -#endif - -#ifdef _PWD_H_ -int pw_copy(int _ffd, int _tfd, const struct passwd *_pw, struct passwd *_old_pw); -struct passwd *pw_dup(const struct passwd *_pw); -int pw_edit(int _notsetuid); -int pw_equal(const struct passwd *_pw1, const struct passwd *_pw2); -void pw_fini(void); -int pw_init(const char *_dir, const char *_master); -char *pw_make(const struct passwd *_pw); -int pw_mkdb(const char *_user); -int pw_lock(void); -struct passwd *pw_scan(const char *_line, int _flags); -const char *pw_tempname(void); -int pw_tmp(int _mfd); -#endif - -#ifdef _GRP_H_ -int gr_equal(const struct group *gr1, const struct group *gr2); -char *gr_make(const struct group *gr); -struct group *gr_dup(const struct group *gr); -struct group *gr_scan(const char *line); -#endif - -#ifdef _SYS_PARAM_H_ -struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr); -int pidfile_write(struct pidfh *pfh); -int pidfile_close(struct pidfh *pfh); -int pidfile_remove(struct pidfh *pfh); -#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 - -/* pw_scan() */ -#define PWSCAN_MASTER 0x01 -#define PWSCAN_WARN 0x02 - -/* humanize_number(3) */ -#define HN_DECIMAL 0x01 -#define HN_NOSPACE 0x02 -#define HN_B 0x04 -#define HN_DIVISOR_1000 0x08 - -#define HN_GETSCALE 0x10 -#define HN_AUTOSCALE 0x20 - -/* hexdump(3) */ -#define HD_COLUMN_MASK 0xff -#define HD_DELIM_MASK 0xff00 -#define HD_OMIT_COUNT (1 << 16) -#define HD_OMIT_HEX (1 << 17) -#define HD_OMIT_CHARS (1 << 18) - -#endif /* !_LIBUTIL_H_ */ diff --git a/libutil/login_cap.c b/libutil/login_cap.c deleted file mode 100644 index 8fee760..0000000 --- a/libutil/login_cap.c +++ /dev/null @@ -1,819 +0,0 @@ -/*- - * 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 <sys/types.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/param.h> -#include <errno.h> -#include <fcntl.h> -#include <libutil.h> -#include <login_cap.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.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 const char ** internal_array = NULL; - -static char path_login_conf[] = _PATH_LOGIN_CONF; - -static char * -allocstr(const 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 const char ** -allocarray(size_t sz) -{ - static const 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 const char ** -arrayize(const char *str, const char *chars, int *size) -{ - int i; - char *ptr; - const char *cptr; - const char **res = NULL; - - /* count the sub-strings */ - for (i = 0, cptr = str; *cptr; i++) { - int count = strcspn(cptr, chars); - cptr += count; - if (*cptr) - ++cptr; - } - - /* alloc the array */ - if ((ptr = allocstr(str)) != NULL) { - if ((res = allocarray(++i)) == NULL) - free((void *)(uintptr_t)(const void *)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 (i.e., "default") is fetched. - * If the name given is LOGIN_MECLASS and - * 'pwd' argument is non-NULL and contains an non-NULL - * dir entry, then the file _FILE_LOGIN_CONF is picked - * up from that directory and used before the system - * login database. In that case the system login database - * is looked up using LOGIN_MECLASS, too, which is a bug. - * Return a filled-out login_cap_t structure, including - * class name, and the capability record buffer. - */ - -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) { - if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1) - login_dbarray[i++] = userpath; - } - /* - * XXX: Why to add the system database if the class is `me'? - */ - if (_secure_path(path_login_conf, 0, 0) != -1) - login_dbarray[i++] = path_login_conf; - login_dbarray[i] = NULL; - - memset(lc, 0, sizeof(login_cap_t)); - 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, 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, name) != 0 && r >= 0) - break; - /* FALLTHROUGH - 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_getpwclass() - * Get the login class for a given password entry from - * the system (only) login class database. - * If the password entry's class field is not set, or - * the class specified does not exist, then use the - * default of LOGIN_DEFCLASS (i.e., "default") for an unprivileged - * user or that of LOGIN_DEFROOTCLASS (i.e., "root") for a super-user. - * Return a filled-out login_cap_t structure, including - * class name, and the capability record buffer. - */ - -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; - } - /* - * XXX: pwd should be unused by login_getclassbyname() unless cls is `me', - * so NULL can be passed instead of pwd for more safety. - */ - return login_getclassbyname(cls, pwd); -} - - -/* - * login_getuserclass() - * Get the `me' login class, allowing user overrides via ~/.login_conf. - * Note that user overrides are allowed only in the `me' class. - */ - -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 default if not found, or - * an error string on error. - */ - -const char * -login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const 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, 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. - */ - -const char ** -login_getcaplist(login_cap_t *lc, const char *cap, const char *chars) -{ - const 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>. - */ - -const char * -login_getpath(login_cap_t *lc, const char *cap, const char *error) -{ - const char *str; - char *ptr; - int count; - - str = login_getcapstr(lc, cap, NULL, NULL); - if (str == NULL) - return error; - ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */ - while (*ptr) { - 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, 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, cap, &res)) == -1) { - long lval; - /* string capability not present, so try for tag#<val> as numeric */ - if ((r = cgetnum(lc->lc_cap, 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, 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, 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"); - */ - -const char * -login_getstyle(login_cap_t *lc, const char *style, const char *auth) -{ - int i; - const char **authtypes = NULL; - char *auths= NULL; - char realauth[64]; - - static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL }; - - if (auth != NULL && *auth != '\0') { - if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)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/libutil/login_cap.h b/libutil/login_cap.h deleted file mode 100644 index 082e34b..0000000 --- a/libutil/login_cap.h +++ /dev/null @@ -1,166 +0,0 @@ -/*- - * 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_SETMAC 0x0100 /* set user default MAC label */ -#define LOGIN_SETCPUMASK 0x0200 /* set user cpumask */ -#define LOGIN_SETALL 0x03ff /* 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 *); - -const char *login_getcapstr(login_cap_t *, const char *, const char *, - const char *); -const char **login_getcaplist(login_cap_t *, const char *, const char *); -const char *login_getstyle(login_cap_t *, const char *, const char *); -rlim_t login_getcaptime(login_cap_t *, const char *, rlim_t, rlim_t); -rlim_t login_getcapnum(login_cap_t *, const char *, rlim_t, rlim_t); -rlim_t login_getcapsize(login_cap_t *, const char *, rlim_t, rlim_t); -const char *login_getpath(login_cap_t *, const char *, const char *); -int login_getcapbool(login_cap_t *, const char *, int); -const char *login_setcryptfmt(login_cap_t *, const char *, const char *); - -int setclasscontext(const char *, unsigned int); -void setclasscpumask(login_cap_t *); -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 *); -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_lt(const login_time_t *, time_t *); -int in_ltm(const login_time_t *, struct tm *, time_t *); -int in_ltms(const login_time_t *, struct tm *, time_t *); -int in_lts(const login_time_t *, time_t *); - -/* helper functions */ - -int login_strinlist(const char **, char const *, int); -int login_str2inlist(const char **, const char *, const char *, int); -login_time_t * login_timelist(login_cap_t *, char const *, int *, - login_time_t **); -int login_ttyok(login_cap_t *, const char *, const char *, const char *); -int login_hostok(login_cap_t *, const char *, const char *, const char *, - const char *); - -__END_DECLS - -#endif /* _LOGIN_CAP_H_ */ diff --git a/libutil/login_crypt.c b/libutil/login_crypt.c deleted file mode 100644 index c65fc9b..0000000 --- a/libutil/login_crypt.c +++ /dev/null @@ -1,50 +0,0 @@ -/*- - * 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", 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/libutil/pw_util.c b/libutil/pw_util.c deleted file mode 100644 index 75459e3..0000000 --- a/libutil/pw_util.c +++ /dev/null @@ -1,621 +0,0 @@ -/*- - * Copyright (c) 1990, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 2002 Networks Associates Technology, Inc. - * All rights reserved. - * - * Portions of this software were developed for the FreeBSD Project by - * ThinkSec AS and NAI Labs, the Security Research Division of Network - * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 - * ("CBOSS"), as part of the DARPA CHATS research program. - * - * 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. - * 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 <ctype.h> -#include <err.h> -#include <fcntl.h> -#include <inttypes.h> -#include <libgen.h> -#include <paths.h> -#include <pwd.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <libutil.h> - -static pid_t editpid = -1; -static int lockfd = -1; -static char masterpasswd[PATH_MAX]; -static char passwd_dir[PATH_MAX]; -static char tempname[PATH_MAX]; -static int initialized; - -#if 0 -void -pw_cont(int sig) -{ - - if (editpid != -1) - kill(editpid, sig); -} -#endif - -/* - * Initialize statics and set limits, signals & umask to try to avoid - * interruptions, crashes etc. that might expose passord data. - */ -int -pw_init(const char *dir, const char *master) -{ -#if 0 - struct rlimit rlim; -#endif - - if (dir == NULL) { - strcpy(passwd_dir, _PATH_ETC); - } else { - if (strlen(dir) >= sizeof(passwd_dir)) { - errno = ENAMETOOLONG; - return (-1); - } - strcpy(passwd_dir, dir); - } - - if (master == NULL) { - if (dir == NULL) { - strcpy(masterpasswd, _PATH_MASTERPASSWD); - } else if (snprintf(masterpasswd, sizeof(masterpasswd), "%s/%s", - passwd_dir, _MASTERPASSWD) > (int)sizeof(masterpasswd)) { - errno = ENAMETOOLONG; - return (-1); - } - } else { - if (strlen(master) >= sizeof(masterpasswd)) { - errno = ENAMETOOLONG; - return (-1); - } - strcpy(masterpasswd, master); - } - - /* - * The code that follows is extremely disruptive to the calling - * process, and is therefore disabled until someone can conceive - * of a realistic scenario where it would fend off a compromise. - * Race conditions concerning the temporary files can be guarded - * against in other ways than masking signals (by checking stat(2) - * results after creation). - */ -#if 0 - /* 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); -#endif - initialized = 1; - return (0); -} - -/* - * Lock the master password file. - */ -int -pw_lock(void) -{ - - if (*masterpasswd == '\0') - return (-1); - - /* - * 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); - /* XXX vulnerable to race conditions */ - if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) { - if (errno == EWOULDBLOCK) { - errx(1, "the password db file is busy"); - } else { - err(1, "could not lock the passwd file: "); - } - } - - /* - * 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) == -1) - err(1, "fstat() failed: "); - if (st.st_nlink != 0) - break; - close(lockfd); - lockfd = -1; - } - return (lockfd); -} - -/* - * Create and open a presumably safe temp file for editing the password - * data, and copy the master password file into it. - */ -int -pw_tmp(int mfd) -{ - char buf[8192]; - ssize_t nr; - const char *p; - int tfd; - - if (*masterpasswd == '\0') - return (-1); - if ((p = strrchr(masterpasswd, '/'))) - ++p; - else - p = masterpasswd; - if (snprintf(tempname, sizeof(tempname), "%.*spw.XXXXXX", - (int)(p - masterpasswd), masterpasswd) >= (int)sizeof(tempname)) { - errno = ENAMETOOLONG; - return (-1); - } - if ((tfd = mkstemp(tempname)) == -1) - return (-1); - if (mfd != -1) { - while ((nr = read(mfd, buf, sizeof(buf))) > 0) - if (write(tfd, buf, (size_t)nr) != nr) - break; - if (nr != 0) { - unlink(tempname); - *tempname = '\0'; - close(tfd); - return (-1); - } - } - return (tfd); -} - -/* - * Regenerate the password database. - */ -int -pw_mkdb(const char *user) -{ - int pstat; - pid_t pid; - - (void)fflush(stderr); - switch ((pid = fork())) { - case -1: - return (-1); - case 0: - /* child */ - if (user == NULL) - execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", - "-d", passwd_dir, tempname, (char *)NULL); - else - execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", - "-d", passwd_dir, "-u", user, tempname, - (char *)NULL); - _exit(1); - /* NOTREACHED */ - default: - /* parent */ - break; - } - if (waitpid(pid, &pstat, 0) == -1) - return (-1); - if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) - return (0); - errno = 0; - return (-1); -} - -/* - * Edit the temp file. Return -1 on error, >0 if the file was modified, 0 - * if it was not. - */ -int -pw_edit(int notsetuid) -{ - struct sigaction sa, sa_int, sa_quit; - sigset_t oldsigset, nsigset; - struct stat st1, st2; - const char *editor; - int pstat; - - if ((editor = getenv("EDITOR")) == NULL) - editor = _PATH_VI; - if (stat(tempname, &st1) == -1) - return (-1); - sa.sa_handler = SIG_IGN; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGINT, &sa, &sa_int); - sigaction(SIGQUIT, &sa, &sa_quit); - sigemptyset(&nsigset); - sigaddset(&nsigset, SIGCHLD); - sigprocmask(SIG_BLOCK, &nsigset, &oldsigset); - switch ((editpid = fork())) { - case -1: - return (-1); - case 0: - sigaction(SIGINT, &sa_int, NULL); - sigaction(SIGQUIT, &sa_quit, NULL); - sigprocmask(SIG_SETMASK, &oldsigset, NULL); - if (notsetuid) { - (void)setgid(getgid()); - (void)setuid(getuid()); - } - errno = 0; - execlp(editor, basename(editor), tempname, (char *)NULL); - _exit(errno); - default: - /* parent */ - break; - } - for (;;) { - if (waitpid(editpid, &pstat, WUNTRACED) == -1) { - if (errno == EINTR) - continue; - unlink(tempname); - editpid = -1; - break; - } else if (WIFSTOPPED(pstat)) { - raise(WSTOPSIG(pstat)); - } else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) { - editpid = -1; - break; - } else { - unlink(tempname); - editpid = -1; - break; - } - } - sigaction(SIGINT, &sa_int, NULL); - sigaction(SIGQUIT, &sa_quit, NULL); - sigprocmask(SIG_SETMASK, &oldsigset, NULL); - if (stat(tempname, &st2) == -1) - return (-1); - return (st1.st_mtime != st2.st_mtime); -} - -/* - * Clean up. Preserve errno for the caller's convenience. - */ -void -pw_fini(void) -{ - int serrno, status; - - if (!initialized) - return; - initialized = 0; - serrno = errno; - if (editpid != -1) { - kill(editpid, SIGTERM); - kill(editpid, SIGCONT); - waitpid(editpid, &status, 0); - editpid = -1; - } - if (*tempname != '\0') { - unlink(tempname); - *tempname = '\0'; - } - if (lockfd != -1) - close(lockfd); - errno = serrno; -} - -/* - * Compares two struct pwds. - */ -int -pw_equal(const struct passwd *pw1, const struct passwd *pw2) -{ - return (strcmp(pw1->pw_name, pw2->pw_name) == 0 && - pw1->pw_uid == pw2->pw_uid && - pw1->pw_gid == pw2->pw_gid && - strcmp(pw1->pw_class, pw2->pw_class) == 0 && - pw1->pw_change == pw2->pw_change && - pw1->pw_expire == pw2->pw_expire && - strcmp(pw1->pw_gecos, pw2->pw_gecos) == 0 && - strcmp(pw1->pw_dir, pw2->pw_dir) == 0 && - strcmp(pw1->pw_shell, pw2->pw_shell) == 0); -} - -/* - * Make a passwd line out of a struct passwd. - */ -char * -pw_make(const struct passwd *pw) -{ - char *line; - - asprintf(&line, "%s:%s:%ju:%ju:%s:%ju:%ju:%s:%s:%s", pw->pw_name, - pw->pw_passwd, (uintmax_t)pw->pw_uid, (uintmax_t)pw->pw_gid, - pw->pw_class, (uintmax_t)pw->pw_change, (uintmax_t)pw->pw_expire, - pw->pw_gecos, pw->pw_dir, pw->pw_shell); - return line; -} - -/* - * Copy password file from one descriptor to another, replacing or adding - * a single record on the way. - */ -int -pw_copy(int ffd, int tfd, const struct passwd *pw, struct passwd *old_pw) -{ - char buf[8192], *end, *line, *p, *q, *r, t; - struct passwd *fpw; - size_t len; - int eof, readlen; - - if ((line = pw_make(pw)) == NULL) - return (-1); - - eof = 0; - len = 0; - p = q = end = buf; - for (;;) { - /* find the end of the current line */ - for (p = q; q < end && *q != '\0'; ++q) - if (*q == '\n') - break; - - /* if we don't have a complete line, fill up the buffer */ - if (q >= end) { - if (eof) - break; - if ((size_t)(q - p) >= sizeof(buf)) { - warnx("passwd line too long"); - errno = EINVAL; /* hack */ - goto err; - } - if (p < end) { - q = memmove(buf, p, end - p); - end -= p - buf; - } else { - p = q = end = buf; - } - readlen = read(ffd, end, sizeof(buf) - (end - buf)); - if (readlen == -1) - goto err; - else - len = (size_t)readlen; - if (len == 0 && p == buf) - break; - end += len; - len = end - buf; - if (len < (ssize_t)sizeof(buf)) { - eof = 1; - if (len > 0 && buf[len - 1] != '\n') - ++len, *end++ = '\n'; - } - continue; - } - - /* is it a blank line or a comment? */ - for (r = p; r < q && isspace(*r); ++r) - /* nothing */ ; - if (r == q || *r == '#') { - /* yep */ - if (write(tfd, p, q - p + 1) != q - p + 1) - goto err; - ++q; - continue; - } - - /* is it the one we're looking for? */ - - t = *q; - *q = '\0'; - - fpw = pw_scan(r, PWSCAN_MASTER); - - /* - * fpw is either the struct passwd for the current line, - * or NULL if the line is malformed. - */ - - *q = t; - if (fpw == NULL || strcmp(fpw->pw_name, pw->pw_name) != 0) { - /* nope */ - if (fpw != NULL) - free(fpw); - if (write(tfd, p, q - p + 1) != q - p + 1) - goto err; - ++q; - continue; - } - if (old_pw && !pw_equal(fpw, old_pw)) { - warnx("entry inconsistent"); - free(fpw); - errno = EINVAL; /* hack */ - goto err; - } - free(fpw); - - /* it is, replace it */ - len = strlen(line); - if (write(tfd, line, len) != (int)len) - goto err; - - /* we're done, just copy the rest over */ - for (;;) { - if (write(tfd, q, end - q) != end - q) - goto err; - q = buf; - readlen = read(ffd, buf, sizeof(buf)); - if (readlen == 0) - break; - else - len = (size_t)readlen; - if (readlen == -1) - goto err; - end = buf + len; - } - goto done; - } - - /* if we got here, we have a new entry */ - len = strlen(line); - if ((size_t)write(tfd, line, len) != len || - write(tfd, "\n", 1) != 1) - goto err; - done: - free(line); - return (0); - err: - free(line); - return (-1); -} - -/* - * Return the current value of tempname. - */ -const char * -pw_tempname(void) -{ - - return (tempname); -} - -/* - * Duplicate a struct passwd. - */ -struct passwd * -pw_dup(const struct passwd *pw) -{ - struct passwd *npw; - ssize_t len; - - len = sizeof(*npw) + - (pw->pw_name ? strlen(pw->pw_name) + 1 : 0) + - (pw->pw_passwd ? strlen(pw->pw_passwd) + 1 : 0) + - (pw->pw_class ? strlen(pw->pw_class) + 1 : 0) + - (pw->pw_gecos ? strlen(pw->pw_gecos) + 1 : 0) + - (pw->pw_dir ? strlen(pw->pw_dir) + 1 : 0) + - (pw->pw_shell ? strlen(pw->pw_shell) + 1 : 0); - if ((npw = malloc((size_t)len)) == NULL) - return (NULL); - memcpy(npw, pw, sizeof(*npw)); - len = sizeof(*npw); - if (pw->pw_name) { - npw->pw_name = ((char *)npw) + len; - len += sprintf(npw->pw_name, "%s", pw->pw_name) + 1; - } - if (pw->pw_passwd) { - npw->pw_passwd = ((char *)npw) + len; - len += sprintf(npw->pw_passwd, "%s", pw->pw_passwd) + 1; - } - if (pw->pw_class) { - npw->pw_class = ((char *)npw) + len; - len += sprintf(npw->pw_class, "%s", pw->pw_class) + 1; - } - if (pw->pw_gecos) { - npw->pw_gecos = ((char *)npw) + len; - len += sprintf(npw->pw_gecos, "%s", pw->pw_gecos) + 1; - } - if (pw->pw_dir) { - npw->pw_dir = ((char *)npw) + len; - len += sprintf(npw->pw_dir, "%s", pw->pw_dir) + 1; - } - if (pw->pw_shell) { - npw->pw_shell = ((char *)npw) + len; - len += sprintf(npw->pw_shell, "%s", pw->pw_shell) + 1; - } - return (npw); -} - -#include "pw_scan.h" - -/* - * Wrapper around an internal libc function - */ -struct passwd * -pw_scan(const char *line, int flags) -{ - struct passwd pw, *ret; - char *bp; - - if ((bp = strdup(line)) == NULL) - return (NULL); - if (!__pw_scan(bp, &pw, flags)) { - free(bp); - return (NULL); - } - ret = pw_dup(&pw); - free(bp); - return (ret); -} |