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.
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.
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]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 #include <sys/param.h>
31 #include <sys/types.h>
42 #define BADLINE "Too many/few fields"
43 #define TOOLONG "Line too long"
44 #define NONAME "No group name"
45 #define BADNAME "Bad character(s) in group name"
46 #define BADGID "Invalid GID"
47 #define NULLNAME "Null login name"
48 #define NOTFOUND "Logname not found in password file"
49 #define DUPNAME "Duplicate logname entry"
50 #define DUPNAME2 "Duplicate logname entry (gid first occurs in passwd entry)"
51 #define NOMEM "Out of memory"
52 #define NGROUPS "Maximum groups exceeded for logname "
53 #define BLANKLINE "Blank line detected. Please remove line"
54 #define LONGNAME "Group name too long"
56 int eflag
, badchar
, baddigit
, badlognam
, colons
, len
;
57 static int longnam
= 0;
60 #define MYBUFSIZE (LINE_MAX) /* max line length including newline and null */
68 void error(char *msg
);
89 fprintf(stderr
, "%s\n", gettext(NOMEM
));
96 main(int argc
, char *argv
[])
99 struct node
*root
= NULL
;
107 char *buf_off
, *tmpbuf
;
108 int delim
[NUM_COLONS
+ 1], buf_len
, bufsize
;
110 (void) setlocale(LC_ALL
, "");
112 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
113 #define TEXT_DOMAIN "SYS_TEST"
115 (void) textdomain(TEXT_DOMAIN
);
118 ngroups_max
= sysconf(_SC_NGROUPS_MAX
);
121 argv
[1] = "/etc/group";
122 else if (argc
!= 2) {
123 fprintf(stderr
, gettext("usage: %s filename\n"), *argv
);
127 if ((fptr
= fopen(argv
[1], "r")) == NULL
) {
128 fprintf(stderr
, gettext("cannot open file %s: %s\n"), argv
[1],
134 while ((pwp
= getpwent()) != NULL
) {
135 t
= (struct node
*)emalloc(sizeof (*t
) + strlen(pwp
->pw_name
));
138 strcpy(t
->user
, pwp
->pw_name
);
143 t
->groups
= (struct group
*)
144 emalloc(sizeof (struct group
));
145 t
->groups
->grp
= pwp
->pw_gid
;
147 t
->groups
->nxt
= NULL
;
153 if ((buf
= malloc(bufsize
)) == NULL
) {
154 (void) fprintf(stderr
, gettext(NOMEM
));
157 while (!feof(fptr
) && !ferror(fptr
)) {
160 while (fgets(buf_off
, (bufsize
- buf_len
), fptr
) != NULL
) {
161 buf_len
+= strlen(buf_off
);
162 if (buf
[buf_len
- 1] == '\n' || feof(fptr
))
164 tmpbuf
= realloc(buf
, (bufsize
+ MYBUFSIZE
));
165 if (tmpbuf
== NULL
) {
166 (void) fprintf(stderr
, gettext(NOMEM
));
169 bufsize
+= MYBUFSIZE
;
171 buf_off
= buf
+ buf_len
;
176 /* Report error to be consistent with libc */
177 if ((buf_len
+ 1) > LINE_MAX
)
181 if (buf
[0] == '\n') /* blank lines are ignored */
183 code
= 1; /* exit with error code = 1 */
184 eflag
= 0; /* force print of "blank" line */
185 fprintf(stderr
, "\n%s %d\n", gettext(BLANKLINE
),
190 if (buf
[buf_len
- 1] == '\n') {
191 if ((tmpbuf
= strdup(buf
)) == NULL
) {
192 (void) fprintf(stderr
, gettext(NOMEM
));
195 tmpbuf
[buf_len
- 1] = ',';
197 if ((tmpbuf
= malloc(buf_len
+ 2)) == NULL
) {
198 (void) fprintf(stderr
, gettext(NOMEM
));
201 (void) strcpy(tmpbuf
, buf
);
202 tmpbuf
[buf_len
++] = ',';
203 tmpbuf
[buf_len
] = '\0';
213 ngroups
++; /* Increment number of groups found */
214 /* Check that entry is not a nameservice redirection */
216 if (buf
[0] == '+' || buf
[0] == '-') {
218 * Should set flag here to allow special case checking
219 * in the rest of the code,
220 * but for now, we'll just ignore this entry.
226 /* Check number of fields */
228 for (i
= 0; buf
[i
] != '\0'; i
++) {
231 if (++colons
> NUM_COLONS
)
235 if (colons
!= NUM_COLONS
) {
241 /* check to see that group name is at least 1 character */
242 /* and that all characters are lowrcase or digits. */
247 for (i
= 0; buf
[i
] != ':'; i
++) {
248 if (i
>= LOGNAME_MAX
)
250 if (!(islower(buf
[i
]) || isdigit(buf
[i
])))
259 /* check that GID is numeric and <= 31 bits */
261 len
= (delim
[2] - delim
[1]) - 1;
263 if (len
> 10 || len
< 1)
266 for (i
= (delim
[1]+1); i
< delim
[2]; i
++) {
267 if (! (isdigit(buf
[i
])))
269 else if (baddigit
== 0)
270 gid
= gid
* 10 + (gid_t
)(buf
[i
] - '0');
271 /* converts ascii GID to decimal */
275 else if (gid
> (gid_t
)MAXUID
)
279 /* check that logname appears in the passwd file */
281 nptr
= &tmpbuf
[delim
[2]];
284 listlen
= strlen(nptr
) - 1;
286 while ((cptr
= strchr(nptr
, ',')) != NULL
) {
295 for (t
= root
; t
!= NULL
; t
= t
->next
) {
296 if (strcmp(t
->user
, nptr
) == 0)
302 * User entry not found, so check if in
307 if ((pwp
= getpwnam(nptr
)) == NULL
) {
315 /* Usrname found, so add entry to user-list */
317 emalloc(sizeof (*t
) + strlen(nptr
));
320 strcpy(t
->user
, nptr
);
325 t
->groups
= (struct group
*)
326 emalloc(sizeof (struct group
));
327 t
->groups
->grp
= pwp
->pw_gid
;
329 t
->groups
->nxt
= NULL
;
339 * check for duplicate logname in group
342 for (gp
= t
->groups
; gp
!= NULL
; gp
= gp
->nxt
) {
343 if (gid
== gp
->grp
) {
344 if (gp
->cnt
++ == 1) {
355 gp
= (struct group
*)emalloc(sizeof (struct group
));
367 fprintf(stderr
, gettext("Group file '%s' is empty\n"), argv
[1]);
372 for (t
= root
; t
!= NULL
; t
= t
->next
) {
373 if (t
->ngroups
> ngroups_max
) {
374 fprintf(stderr
, "\n\n%s%s (%d)\n",
375 NGROUPS
, t
->user
, t
->ngroups
);
383 /* Error printing routine */
390 fprintf(stderr
, "\n\n%s", buf
);
394 fprintf(stderr
, "\t%s\n", gettext(msg
));
399 fprintf(stderr
, "\t%d %s\n", badchar
, gettext(msg
));
402 } else if (baddigit
!= 0) {
403 fprintf(stderr
, "\t%s\n", gettext(msg
));
406 } else if (badlognam
!= 0) {
407 fprintf(stderr
, "\t%s - %s\n", nptr
, gettext(msg
));
411 fprintf(stderr
, "\t%s\n", gettext(msg
));