11553Srgrimes/*- 21553Srgrimes * Copyright (c) 1990, 1993, 1994 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 4. Neither the name of the University nor the names of its contributors 141553Srgrimes * may be used to endorse or promote products derived from this software 151553Srgrimes * without specific prior written permission. 161553Srgrimes * 171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271553Srgrimes * SUCH DAMAGE. 281553Srgrimes */ 291553Srgrimes 3090039Sobrien#if defined(LIBC_SCCS) && !defined(lint) 311553Srgrimesstatic char sccsid[] = "@(#)pw_scan.c 8.3 (Berkeley) 4/2/94"; 3290039Sobrien#endif /* LIBC_SCCS and not lint */ 3390039Sobrien#include <sys/cdefs.h> 3490039Sobrien__FBSDID("$FreeBSD$"); 351553Srgrimes 361553Srgrimes/* 371553Srgrimes * This module is used to "verify" password entries by chpass(1) and 381553Srgrimes * pwd_mkdb(8). 391553Srgrimes */ 401553Srgrimes 411553Srgrimes#include <sys/param.h> 421553Srgrimes 431553Srgrimes#include <err.h> 4457868Spaul#include <errno.h> 451553Srgrimes#include <fcntl.h> 461553Srgrimes#include <pwd.h> 471553Srgrimes#include <stdio.h> 481553Srgrimes#include <string.h> 491553Srgrimes#include <stdlib.h> 501553Srgrimes#include <unistd.h> 511553Srgrimes 521553Srgrimes#include "pw_scan.h" 531553Srgrimes 5453183Ssheldonh/* 5553183Ssheldonh * Some software assumes that IDs are short. We should emit warnings 5691925Sdd * for id's which cannot be stored in a short, but we are more liberal 5753183Ssheldonh * by default, warning for IDs greater than USHRT_MAX. 5854034Ssheldonh * 5991925Sdd * If pw_big_ids_warning is -1 on entry to pw_scan(), it will be set based 6091925Sdd * on the existence of PW_SCAN_BIG_IDS in the environment. 61195827Skensmith * 62195827Skensmith * It is believed all baseline system software that can not handle the 63195827Skensmith * normal ID sizes is now gone so pw_big_ids_warning is disabled for now. 64195827Skensmith * But the code has been left in place in case end-users want to re-enable 65195827Skensmith * it and/or for the next time the ID sizes get bigger but pieces of the 66195827Skensmith * system lag behind. 6753183Ssheldonh */ 68195827Skensmithstatic int pw_big_ids_warning = 0; 6953183Ssheldonh 701553Srgrimesint 7165532Snectar__pw_scan(char *bp, struct passwd *pw, int flags) 721553Srgrimes{ 7357868Spaul uid_t id; 741553Srgrimes int root; 75103958Smaxim char *ep, *p, *sh; 76195827Skensmith unsigned long temp; 771553Srgrimes 7854034Ssheldonh if (pw_big_ids_warning == -1) 7954034Ssheldonh pw_big_ids_warning = getenv("PW_SCAN_BIG_IDS") == NULL ? 1 : 0; 8054034Ssheldonh 812916Swollman pw->pw_fields = 0; 821553Srgrimes if (!(pw->pw_name = strsep(&bp, ":"))) /* login */ 831553Srgrimes goto fmt; 841553Srgrimes root = !strcmp(pw->pw_name, "root"); 8587348Sdes if (pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0')) 862916Swollman pw->pw_fields |= _PWF_NAME; 871553Srgrimes 881553Srgrimes if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */ 891553Srgrimes goto fmt; 9087348Sdes if (pw->pw_passwd[0]) 9187348Sdes pw->pw_fields |= _PWF_PASSWD; 921553Srgrimes 931553Srgrimes if (!(p = strsep(&bp, ":"))) /* uid */ 941553Srgrimes goto fmt; 9552921Seivind if (p[0]) 9652921Seivind pw->pw_fields |= _PWF_UID; 9752921Seivind else { 9853581Seivind if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') { 9965532Snectar if (flags & _PWSCAN_WARN) 10065532Snectar warnx("no uid for user %s", pw->pw_name); 10153581Seivind return (0); 10253581Seivind } 10352921Seivind } 104195827Skensmith errno = 0; 105195827Skensmith temp = strtoul(p, &ep, 10); 106195827Skensmith if ((temp == ULONG_MAX && errno == ERANGE) || temp > UID_MAX) { 10765532Snectar if (flags & _PWSCAN_WARN) 108195827Skensmith warnx("%s > max uid value (%u)", p, UID_MAX); 10957868Spaul return (0); 11057868Spaul } 111195827Skensmith id = temp; 112104348Smaxim if (*ep != '\0') { 113103958Smaxim if (flags & _PWSCAN_WARN) 114103958Smaxim warnx("%s uid is incorrect", p); 115103958Smaxim return (0); 116103958Smaxim } 1171553Srgrimes if (root && id) { 11865532Snectar if (flags & _PWSCAN_WARN) 11965532Snectar warnx("root uid should be 0"); 1201553Srgrimes return (0); 1211553Srgrimes } 12265532Snectar if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) { 12357868Spaul warnx("%s > recommended max uid value (%u)", p, USHRT_MAX); 12450700Ssheldonh /*return (0);*/ /* THIS SHOULD NOT BE FATAL! */ 1251553Srgrimes } 1261553Srgrimes pw->pw_uid = id; 1271553Srgrimes 1281553Srgrimes if (!(p = strsep(&bp, ":"))) /* gid */ 1291553Srgrimes goto fmt; 13087348Sdes if (p[0]) 13187348Sdes pw->pw_fields |= _PWF_GID; 132104891Smaxim else { 133104891Smaxim if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') { 134104891Smaxim if (flags & _PWSCAN_WARN) 135104891Smaxim warnx("no gid for user %s", pw->pw_name); 136104891Smaxim return (0); 137104891Smaxim } 138104891Smaxim } 139195827Skensmith errno = 0; 140195827Skensmith temp = strtoul(p, &ep, 10); 141195827Skensmith if ((temp == ULONG_MAX && errno == ERANGE) || temp > GID_MAX) { 14265532Snectar if (flags & _PWSCAN_WARN) 143195827Skensmith warnx("%s > max gid value (%u)", p, GID_MAX); 14457868Spaul return (0); 14557868Spaul } 146195827Skensmith id = temp; 147104348Smaxim if (*ep != '\0') { 148103958Smaxim if (flags & _PWSCAN_WARN) 149103958Smaxim warnx("%s gid is incorrect", p); 150103958Smaxim return (0); 151103958Smaxim } 15265532Snectar if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) { 15357868Spaul warnx("%s > recommended max gid value (%u)", p, USHRT_MAX); 15450700Ssheldonh /* return (0); This should not be fatal! */ 1551553Srgrimes } 1561553Srgrimes pw->pw_gid = id; 1571553Srgrimes 15865532Snectar if (flags & _PWSCAN_MASTER ) { 15987348Sdes if (!(pw->pw_class = strsep(&bp, ":"))) /* class */ 16087347Sdes goto fmt; 16187348Sdes if (pw->pw_class[0]) 16287348Sdes pw->pw_fields |= _PWF_CLASS; 16365532Snectar 16487348Sdes if (!(p = strsep(&bp, ":"))) /* change */ 16565532Snectar goto fmt; 16687348Sdes if (p[0]) 16787348Sdes pw->pw_fields |= _PWF_CHANGE; 16865532Snectar pw->pw_change = atol(p); 16965532Snectar 17087348Sdes if (!(p = strsep(&bp, ":"))) /* expire */ 17165532Snectar goto fmt; 17287348Sdes if (p[0]) 17387348Sdes pw->pw_fields |= _PWF_EXPIRE; 17465532Snectar pw->pw_expire = atol(p); 17565532Snectar } 1765964Sdg if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */ 1775964Sdg goto fmt; 17887348Sdes if (pw->pw_gecos[0]) 17987348Sdes pw->pw_fields |= _PWF_GECOS; 1802916Swollman 18187348Sdes if (!(pw->pw_dir = strsep(&bp, ":"))) /* directory */ 1825964Sdg goto fmt; 18387348Sdes if (pw->pw_dir[0]) 18487348Sdes pw->pw_fields |= _PWF_DIR; 1852916Swollman 1861553Srgrimes if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */ 1871553Srgrimes goto fmt; 1881553Srgrimes 1891553Srgrimes p = pw->pw_shell; 190124690Scharnier if (root && *p) { /* empty == /bin/sh */ 1911553Srgrimes for (setusershell();;) { 1921553Srgrimes if (!(sh = getusershell())) { 19365532Snectar if (flags & _PWSCAN_WARN) 19465532Snectar warnx("warning, unknown root shell"); 1951553Srgrimes break; 1961553Srgrimes } 1971553Srgrimes if (!strcmp(p, sh)) 1988857Srgrimes break; 1991553Srgrimes } 200124690Scharnier endusershell(); 201124690Scharnier } 20287348Sdes if (p[0]) 20387348Sdes pw->pw_fields |= _PWF_SHELL; 2041553Srgrimes 20530260Scharnier if ((p = strsep(&bp, ":"))) { /* too many */ 20665532Snectarfmt: 20765532Snectar if (flags & _PWSCAN_WARN) 20865532Snectar warnx("corrupted entry"); 2091553Srgrimes return (0); 2101553Srgrimes } 2111553Srgrimes return (1); 2121553Srgrimes} 213