xref: /illumos-gate/usr/src/cmd/pwck/pwck.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/signal.h>
35 #include <sys/sysmacros.h>
36 #include <sys/stat.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <locale.h>
42 #include <errno.h>
43 #include <unistd.h>
44 
45 #define	ERROR1	"Too many/few fields"
46 #define	ERROR2	"Bad character(s) in logname"
47 #define	ERROR2a "First char in logname not alphabetic"
48 #define	ERROR2b "Logname field NULL"
49 #define	ERROR2c "Logname contains no lower-case letters"
50 #define	ERROR3	"Logname too long/short"
51 #define	ERROR4	"Invalid UID"
52 #define	ERROR5	"Invalid GID"
53 #define	ERROR6	"Login directory not found"
54 #define	ERROR6a	"Login directory null"
55 #define	ERROR7	"Optional shell file not found"
56 
57 static int eflag, code = 0;
58 static int badc;
59 static int lc;
60 static char buf[512];
61 static void error(char *);
62 
63 int
64 main(int argc, char **argv)
65 {
66 	int delim[512];
67 	char logbuf[512];
68 	FILE *fptr;
69 	struct stat obuf;
70 	uid_t uid;
71 	gid_t gid;
72 	int i, j, colons;
73 	char *pw_file;
74 	struct stat stat_buf;
75 	char *str, *lastc;
76 
77 	(void) setlocale(LC_ALL, "");
78 
79 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
80 #define	TEXT_DOMAIN "SYS_TEST"
81 #endif
82 	(void) textdomain(TEXT_DOMAIN);
83 
84 	if (argc == 1)
85 		pw_file = "/etc/passwd";
86 	else
87 		pw_file = argv[1];
88 
89 	if ((fptr = fopen(pw_file, "r")) == NULL) {
90 		(void) fprintf(stderr, gettext("cannot open %s\n"), pw_file);
91 		exit(1);
92 	}
93 
94 	if (fstat(fileno(fptr), &stat_buf) < 0) {
95 		(void) fprintf(stderr, gettext("fstat failed for %s\n"),
96 		    pw_file);
97 		(void) fclose(fptr);
98 		exit(1);
99 	}
100 
101 	if (stat_buf.st_size == 0) {
102 		(void) fprintf(stderr, gettext("file %s is empty\n"), pw_file);
103 		(void) fclose(fptr);
104 		exit(1);
105 	}
106 
107 	while (fgets(buf, sizeof (buf), fptr) != NULL) {
108 
109 		colons = 0;
110 		badc = 0;
111 		lc = 0;
112 		eflag = 0;
113 
114 		/* Check that entry is not a nameservice redirection */
115 
116 		if (buf[0] == '+' || buf[0] == '-')  {
117 			/*
118 			 * Should set flag here to allow special case checking
119 			 * in the rest of the code,
120 			 * but for now, we'll just ignore this entry.
121 			 */
122 			continue;
123 		}
124 
125 		/* Check number of fields */
126 
127 		for (i = 0; buf[i] != NULL; i++)
128 			if (buf[i] == ':') {
129 				delim[colons] = i;
130 				++colons;
131 			}
132 
133 		if (colons != 6) {
134 			error(ERROR1);
135 			continue;
136 		}
137 		delim[6] = i - 1;
138 		delim[7] = NULL;
139 
140 		/*
141 		 * Check the first char is alpha; the rest alphanumeric;
142 		 * and that the name does not consist solely of uppercase
143 		 * alpha chars
144 		 */
145 		if (buf[0] == ':')
146 			error(ERROR2b);
147 		else if (!isalpha(buf[0]))
148 			error(ERROR2a);
149 
150 		for (i = 0; buf[i] != ':'; i++) {
151 			if (!isalnum(buf[i]) &&
152 				buf[i] != '_' &&
153 				buf[i] != '-' &&
154 				buf[i] != '.')
155 				badc++;
156 			else if (islower(buf[i]))
157 				lc++;
158 		}
159 		if (lc == 0)
160 			error(ERROR2c);
161 		if (badc > 0)
162 			error(ERROR2);
163 
164 		/* Check for valid number of characters in logname */
165 
166 		if (i <= 0 || i > 8)
167 			error(ERROR3);
168 
169 		/* Check that UID is numeric and <= MAXUID */
170 
171 		errno = 0;
172 		str = &buf[delim[1] + 1];
173 		uid = strtol(str, &lastc, 10);
174 		if (lastc != str + (delim[2] - delim[1]) - 1 ||
175 		    uid > MAXUID || errno == ERANGE)
176 			error(ERROR4);
177 
178 		/* Check that GID is numeric and <= MAXUID */
179 
180 		errno = 0;
181 		str = &buf[delim[2] + 1];
182 		gid = strtol(str, &lastc, 10);
183 		if (lastc != str + (delim[3] - delim[2]) - 1 ||
184 		    gid > MAXUID || errno == ERANGE)
185 			error(ERROR5);
186 
187 		/* Check initial working directory */
188 
189 		for (j = 0, i = (delim[4] + 1); i < delim[5]; j++, i++)
190 			logbuf[j] = buf[i];
191 		logbuf[j] = '\0';
192 
193 		if (logbuf[0] == NULL)
194 			error(ERROR6a);
195 		else if ((stat(logbuf, &obuf)) == -1)
196 			error(ERROR6);
197 
198 		/* Check program to use as shell  */
199 
200 		if ((buf[(delim[5] + 1)]) != '\n') {
201 
202 			for (j = 0, i = (delim[5] + 1); i < delim[6]; j++, i++)
203 				logbuf[j] = buf[i];
204 			logbuf[j] = '\0';
205 
206 			if (strcmp(logbuf, "*") == 0)	/* subsystem login */
207 				continue;
208 
209 			if ((stat(logbuf, &obuf)) == -1)
210 				error(ERROR7);
211 
212 			for (j = 0; j < 512; j++)
213 				logbuf[j] = NULL;
214 		}
215 	}
216 	(void) fclose(fptr);
217 	return (code);
218 }
219 
220 /* Error printing routine */
221 
222 static void
223 error(char *msg)
224 {
225 	if (!eflag) {
226 		(void) fprintf(stderr, "\n%s", buf);
227 		code = 1;
228 		++eflag;
229 	}
230 	if (!badc)
231 		(void) fprintf(stderr, "\t%s\n", gettext(msg));
232 	else {
233 		(void) fprintf(stderr, "\t%d %s\n", badc, gettext(msg));
234 		badc = 0;
235 	}
236 }
237