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 #pragma ident "%Z%%M% %I% %E% SMI"
32 #include <sys/param.h>
33 #include <sys/types.h>
44 #define BADLINE "Too many/few fields"
45 #define TOOLONG "Line too long"
46 #define NONAME "No group name"
47 #define BADNAME "Bad character(s) in group name"
48 #define BADGID "Invalid GID"
49 #define NULLNAME "Null login name"
50 #define NOTFOUND "Logname not found in password file"
51 #define DUPNAME "Duplicate logname entry"
52 #define DUPNAME2 "Duplicate logname entry (gid first occurs in passwd entry)"
53 #define NOMEM "Out of memory"
54 #define NGROUPS "Maximum groups exceeded for logname "
55 #define BLANKLINE "Blank line detected. Please remove line"
56 #define LONGNAME "Group name too long"
58 int eflag
, badchar
, baddigit
, badlognam
, colons
, len
;
59 static int longnam
= 0;
62 #define MYBUFSIZE (LINE_MAX) /* max line length including newline and null */
70 void error(char *msg
);
91 fprintf(stderr
, "%s\n", gettext(NOMEM
));
98 main(int argc
, char *argv
[])
101 struct node
*root
= NULL
;
109 char *buf_off
, *tmpbuf
;
110 int delim
[NUM_COLONS
+ 1], buf_len
, bufsize
;
112 (void) setlocale(LC_ALL
, "");
114 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
115 #define TEXT_DOMAIN "SYS_TEST"
117 (void) textdomain(TEXT_DOMAIN
);
120 ngroups_max
= sysconf(_SC_NGROUPS_MAX
);
123 argv
[1] = "/etc/group";
124 else if (argc
!= 2) {
125 fprintf(stderr
, gettext("usage: %s filename\n"), *argv
);
129 if ((fptr
= fopen(argv
[1], "r")) == NULL
) {
130 fprintf(stderr
, gettext("cannot open file %s: %s\n"), argv
[1],
136 while ((pwp
= getpwent()) != NULL
) {
137 t
= (struct node
*)emalloc(sizeof (*t
) + strlen(pwp
->pw_name
));
140 strcpy(t
->user
, pwp
->pw_name
);
145 t
->groups
= (struct group
*)
146 emalloc(sizeof (struct group
));
147 t
->groups
->grp
= pwp
->pw_gid
;
149 t
->groups
->nxt
= NULL
;
155 if ((buf
= malloc(bufsize
)) == NULL
) {
156 (void) fprintf(stderr
, gettext(NOMEM
));
159 while (!feof(fptr
) && !ferror(fptr
)) {
162 while (fgets(buf_off
, (bufsize
- buf_len
), fptr
) != NULL
) {
163 buf_len
+= strlen(buf_off
);
164 if (buf
[buf_len
- 1] == '\n' || feof(fptr
))
166 tmpbuf
= realloc(buf
, (bufsize
+ MYBUFSIZE
));
167 if (tmpbuf
== NULL
) {
168 (void) fprintf(stderr
, gettext(NOMEM
));
171 bufsize
+= MYBUFSIZE
;
173 buf_off
= buf
+ buf_len
;
178 /* Report error to be consistent with libc */
179 if ((buf_len
+ 1) > LINE_MAX
)
183 if (buf
[0] == '\n') /* blank lines are ignored */
185 code
= 1; /* exit with error code = 1 */
186 eflag
= 0; /* force print of "blank" line */
187 fprintf(stderr
, "\n%s %d\n", gettext(BLANKLINE
),
192 if (buf
[buf_len
- 1] == '\n') {
193 if ((tmpbuf
= strdup(buf
)) == NULL
) {
194 (void) fprintf(stderr
, gettext(NOMEM
));
197 tmpbuf
[buf_len
- 1] = ',';
199 if ((tmpbuf
= malloc(buf_len
+ 2)) == NULL
) {
200 (void) fprintf(stderr
, gettext(NOMEM
));
203 (void) strcpy(tmpbuf
, buf
);
204 tmpbuf
[buf_len
++] = ',';
205 tmpbuf
[buf_len
] = '\0';
215 ngroups
++; /* Increment number of groups found */
216 /* Check that entry is not a nameservice redirection */
218 if (buf
[0] == '+' || buf
[0] == '-') {
220 * Should set flag here to allow special case checking
221 * in the rest of the code,
222 * but for now, we'll just ignore this entry.
228 /* Check number of fields */
230 for (i
= 0; buf
[i
] != NULL
; i
++) {
233 if (++colons
> NUM_COLONS
)
237 if (colons
!= NUM_COLONS
) {
243 /* check to see that group name is at least 1 character */
244 /* and that all characters are lowrcase or digits. */
249 for (i
= 0; buf
[i
] != ':'; i
++) {
250 if (i
>= LOGNAME_MAX
)
252 if (!(islower(buf
[i
]) || isdigit(buf
[i
])))
261 /* check that GID is numeric and <= 31 bits */
263 len
= (delim
[2] - delim
[1]) - 1;
265 if (len
> 10 || len
< 1)
268 for (i
= (delim
[1]+1); i
< delim
[2]; i
++) {
269 if (! (isdigit(buf
[i
])))
271 else if (baddigit
== 0)
272 gid
= gid
* 10 + (gid_t
)(buf
[i
] - '0');
273 /* converts ascii GID to decimal */
277 else if (gid
> (gid_t
)MAXUID
)
281 /* check that logname appears in the passwd file */
283 nptr
= &tmpbuf
[delim
[2]];
286 listlen
= strlen(nptr
) - 1;
288 while ((cptr
= strchr(nptr
, ',')) != NULL
) {
297 for (t
= root
; t
!= NULL
; t
= t
->next
) {
298 if (strcmp(t
->user
, nptr
) == 0)
304 * User entry not found, so check if in
309 if ((pwp
= getpwnam(nptr
)) == NULL
) {
317 /* Usrname found, so add entry to user-list */
319 emalloc(sizeof (*t
) + strlen(nptr
));
322 strcpy(t
->user
, nptr
);
327 t
->groups
= (struct group
*)
328 emalloc(sizeof (struct group
));
329 t
->groups
->grp
= pwp
->pw_gid
;
331 t
->groups
->nxt
= NULL
;
341 * check for duplicate logname in group
344 for (gp
= t
->groups
; gp
!= NULL
; gp
= gp
->nxt
) {
345 if (gid
== gp
->grp
) {
346 if (gp
->cnt
++ == 1) {
357 gp
= (struct group
*)emalloc(sizeof (struct group
));
369 fprintf(stderr
, gettext("Group file '%s' is empty\n"), argv
[1]);
374 for (t
= root
; t
!= NULL
; t
= t
->next
) {
375 if (t
->ngroups
> ngroups_max
) {
376 fprintf(stderr
, "\n\n%s%s (%d)\n",
377 NGROUPS
, t
->user
, t
->ngroups
);
385 /* Error printing routine */
392 fprintf(stderr
, "\n\n%s", buf
);
396 fprintf(stderr
, "\t%s\n", gettext(msg
));
401 fprintf(stderr
, "\t%d %s\n", badchar
, gettext(msg
));
404 } else if (baddigit
!= 0) {
405 fprintf(stderr
, "\t%s\n", gettext(msg
));
408 } else if (badlognam
!= 0) {
409 fprintf(stderr
, "\t%s - %s\n", nptr
, gettext(msg
));
413 fprintf(stderr
, "\t%s\n", gettext(msg
));