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