1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1988, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 2002 Networks Associates Technology, Inc. 7 * All rights reserved. 8 * 9 * Portions of this software were developed for the FreeBSD Project by 10 * ThinkSec AS and NAI Labs, the Security Research Division of Network 11 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 12 * ("CBOSS"), as part of the DARPA CHATS research program. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 */ 42 43 #if 0 44 #endif 45 46 #include <sys/cdefs.h> 47 #include <sys/param.h> 48 #include <sys/stat.h> 49 50 #include <ctype.h> 51 #include <err.h> 52 #include <errno.h> 53 #include <grp.h> 54 #include <paths.h> 55 #include <pwd.h> 56 #include <stdlib.h> 57 #include <string.h> 58 59 #include "chpass.h" 60 61 /* ARGSUSED */ 62 int 63 p_login(char *p, struct passwd *pw, ENTRY *ep __unused) 64 { 65 if (!*p) { 66 warnx("empty login field"); 67 return (-1); 68 } 69 if (*p == '-') { 70 warnx("login names may not begin with a hyphen"); 71 return (-1); 72 } 73 if (!(pw->pw_name = strdup(p))) { 74 warnx("can't save entry"); 75 return (-1); 76 } 77 if (strchr(p, '.')) 78 warnx("\'.\' is dangerous in a login name"); 79 for (; *p; ++p) 80 if (isupper(*p)) { 81 warnx("upper-case letters are dangerous in a login name"); 82 break; 83 } 84 return (0); 85 } 86 87 /* ARGSUSED */ 88 int 89 p_passwd(char *p, struct passwd *pw, ENTRY *ep __unused) 90 { 91 if (!(pw->pw_passwd = strdup(p))) { 92 warnx("can't save password entry"); 93 return (-1); 94 } 95 96 return (0); 97 } 98 99 /* ARGSUSED */ 100 int 101 p_uid(char *p, struct passwd *pw, ENTRY *ep __unused) 102 { 103 uid_t id; 104 char *np; 105 106 if (!*p) { 107 warnx("empty uid field"); 108 return (-1); 109 } 110 if (!isdigit(*p)) { 111 warnx("illegal uid"); 112 return (-1); 113 } 114 errno = 0; 115 id = strtoul(p, &np, 10); 116 if (*np || (id == (uid_t)ULONG_MAX && errno == ERANGE)) { 117 warnx("illegal uid"); 118 return (-1); 119 } 120 pw->pw_uid = id; 121 return (0); 122 } 123 124 /* ARGSUSED */ 125 int 126 p_gid(char *p, struct passwd *pw, ENTRY *ep __unused) 127 { 128 struct group *gr; 129 gid_t id; 130 char *np; 131 132 if (!*p) { 133 warnx("empty gid field"); 134 return (-1); 135 } 136 if (!isdigit(*p)) { 137 if (!(gr = getgrnam(p))) { 138 warnx("unknown group %s", p); 139 return (-1); 140 } 141 pw->pw_gid = gr->gr_gid; 142 return (0); 143 } 144 errno = 0; 145 id = strtoul(p, &np, 10); 146 if (*np || (id == (uid_t)ULONG_MAX && errno == ERANGE)) { 147 warnx("illegal gid"); 148 return (-1); 149 } 150 pw->pw_gid = id; 151 return (0); 152 } 153 154 /* ARGSUSED */ 155 int 156 p_class(char *p, struct passwd *pw, ENTRY *ep __unused) 157 { 158 if (!(pw->pw_class = strdup(p))) { 159 warnx("can't save entry"); 160 return (-1); 161 } 162 163 return (0); 164 } 165 166 /* ARGSUSED */ 167 int 168 p_change(char *p, struct passwd *pw, ENTRY *ep __unused) 169 { 170 if (!atot(p, &pw->pw_change)) 171 return (0); 172 warnx("illegal date for change field"); 173 return (-1); 174 } 175 176 /* ARGSUSED */ 177 int 178 p_expire(char *p, struct passwd *pw, ENTRY *ep __unused) 179 { 180 if (!atot(p, &pw->pw_expire)) 181 return (0); 182 warnx("illegal date for expire field"); 183 return (-1); 184 } 185 186 /* ARGSUSED */ 187 int 188 p_gecos(char *p, struct passwd *pw __unused, ENTRY *ep) 189 { 190 if (!(ep->save = strdup(p))) { 191 warnx("can't save entry"); 192 return (-1); 193 } 194 return (0); 195 } 196 197 /* ARGSUSED */ 198 int 199 p_hdir(char *p, struct passwd *pw, ENTRY *ep __unused) 200 { 201 if (!*p) { 202 warnx("empty home directory field"); 203 return (-1); 204 } 205 if (!(pw->pw_dir = strdup(p))) { 206 warnx("can't save entry"); 207 return (-1); 208 } 209 return (0); 210 } 211 212 /* ARGSUSED */ 213 int 214 p_shell(char *p, struct passwd *pw, ENTRY *ep __unused) 215 { 216 struct stat sbuf; 217 218 if (!*p) { 219 pw->pw_shell = strdup(_PATH_BSHELL); 220 return (0); 221 } 222 /* only admin can change from or to "restricted" shells */ 223 if (!master_mode && pw->pw_shell && !ok_shell(pw->pw_shell)) { 224 warnx("%s: current shell non-standard", pw->pw_shell); 225 return (-1); 226 } 227 if (!ok_shell(p)) { 228 if (!master_mode) { 229 warnx("%s: non-standard shell", p); 230 return (-1); 231 } 232 pw->pw_shell = strdup(p); 233 } 234 else 235 pw->pw_shell = dup_shell(p); 236 if (!pw->pw_shell) { 237 warnx("can't save entry"); 238 return (-1); 239 } 240 if (stat(pw->pw_shell, &sbuf) < 0) { 241 if (errno == ENOENT) 242 warnx("WARNING: shell '%s' does not exist", 243 pw->pw_shell); 244 else 245 warn("WARNING: can't stat shell '%s'", pw->pw_shell); 246 return (0); 247 } 248 if (!S_ISREG(sbuf.st_mode)) { 249 warnx("WARNING: shell '%s' is not a regular file", 250 pw->pw_shell); 251 return (0); 252 } 253 if ((sbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) == 0) { 254 warnx("WARNING: shell '%s' is not executable", pw->pw_shell); 255 return (0); 256 } 257 return (0); 258 } 259