2 Copyright (C) 2009-2024 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Jim Meyering. */
27 #include <sys/types.h>
33 #define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
40 const char *user_name
;
41 const char *group_name
;
45 static struct test T
[] =
47 { "", -1, -1, "", "", NULL
},
48 { ":", -1, -1, "", "", NULL
},
49 { "+0:+0", 0, 0, "", "", NULL
},
50 { "+0:+0", 0, 0, "", "", NULL
},
51 { ":+1", -1, 1, "", "", NULL
},
52 { "+1", 1, -1, "", "", NULL
},
53 { ":+0", -1, 0, "", "", NULL
},
54 { "+22:+42", 22, 42, "", "", NULL
},
55 /* (uint32_t)-1 should be invalid everywhere */
56 { "+4294967295:+4294967295", 0, 0, NULL
, NULL
, "invalid user"},
57 /* likewise, but with only the group being invalid */
58 { "+0:+4294967295", 0, 0, NULL
, NULL
, "invalid group"},
59 { ":+4294967295", 0, 0, NULL
, NULL
, "invalid group"},
60 /* and only the user being invalid */
61 { "+4294967295:+0", 0, 0, NULL
, NULL
, "invalid user"},
63 { "+4294967296:+4294967296", 0, 0, NULL
, NULL
, "invalid user"},
64 { "+0:+4294967296", 0, 0, NULL
, NULL
, "invalid group"},
65 { ":+4294967296", 0, 0, NULL
, NULL
, "invalid group"},
66 { "+4294967296:+0", 0, 0, NULL
, NULL
, "invalid user"},
67 /* numeric user and no group is invalid */
68 { "+4294967295:", 0, 0, NULL
, NULL
, "invalid spec"},
69 { "+4294967296:", 0, 0, NULL
, NULL
, "invalid spec"},
70 { "+1:", 0, 0, NULL
, NULL
, "invalid spec"},
71 { "+0:", 0, 0, NULL
, NULL
, "invalid spec"},
73 /* "username:" must expand to UID:GID where GID is username's login group */
74 /* Add an entry like the following to the table, if possible.
75 { "U_NAME:", UID,GID, U_NAME, G_NAME, NULL}, */
76 { "" /* placeholder */, -1, -1, "", "", NULL
},
79 #define STREQ(a, b) (strcmp (a, b) == 0)
82 maybe_null (char const *s
)
84 return s
? s
: "NULL";
88 same_diag (char const *s
, char const *t
)
90 if (s
== NULL
&& t
== NULL
)
92 if (s
== NULL
|| t
== NULL
)
103 /* Find a UID that has both a user name and login group name,
107 for (uid
= 1200; 0 < uid
; uid
--)
110 struct passwd
*pw
= getpwuid (uid
);
113 if (!pw
|| !pw
->pw_name
|| !(gr
= getgrgid (pw
->pw_gid
)) || !gr
->gr_name
)
115 j
= ARRAY_CARDINALITY (T
) - 1;
116 len
= strlen (pw
->pw_name
);
117 if (sizeof T
[j
].in
- 2 < len
)
120 /* Store "username:" in T[j].in. */
121 memcpy(T
[j
].in
, pw
->pw_name
, len
);
122 strcpy(T
[j
].in
+ len
, ":");
125 T
[j
].gid
= gr
->gr_gid
;
126 T
[j
].user_name
= xstrdup (pw
->pw_name
);
127 T
[j
].group_name
= xstrdup (gr
->gr_name
);
133 char *user_name
= NULL
;
134 char *group_name
= NULL
;
136 for (i
= 0; i
< ARRAY_CARDINALITY (T
); i
++)
138 uid_t uid
= (uid_t
) -1;
139 gid_t gid
= (gid_t
) -1;
142 char const *diag
= parse_user_spec (T
[i
].in
, &uid
, &gid
,
143 &user_name
, &group_name
);
144 if (!same_diag (diag
, T
[i
].result
))
146 printf ("%s return value mismatch: got %s, expected %s\n",
147 T
[i
].in
, maybe_null (diag
), maybe_null (T
[i
].result
));
155 if (uid
!= T
[i
].uid
|| gid
!= T
[i
].gid
)
157 printf ("%s mismatch (-: expected uid,gid; +:actual)\n"
158 "-%3lu,%3lu\n+%3lu,%3lu\n",
160 (unsigned long int) T
[i
].uid
,
161 (unsigned long int) T
[i
].gid
,
162 (unsigned long int) uid
,
163 (unsigned long int) gid
);
169 /* Expected a non-NULL result diagnostic, yet got NULL. */
171 printf ("%s diagnostic mismatch (-: expected diagnostic; +:actual)\n"
172 "-%s\n+%s\n", T
[i
].in
, T
[i
].result
, diag
);
177 /* Should get the same result, but with a warning, if replacing
179 char *colon
= strchr (T
[i
].in
, ':');
185 char *user_name2
= NULL
;
186 char *group_name2
= NULL
;
188 if (! (parse_user_spec_warn (T
[i
].in
, &uid2
, &gid2
,
189 &user_name2
, &group_name2
, &warn
)
191 printf ("%s did not warn\n", T
[i
].in
);
192 else if (! (uid
== uid2
&& gid
== gid2
193 && !!user_name
== !!user_name2
194 && (!user_name
|| STREQ (user_name
, user_name2
))
195 && !!group_name
== !!group_name2
196 && (!group_name
|| STREQ (group_name
, group_name2
))))
197 printf ("%s treated differently than with colon\n", T
[i
].in
);
205 /* Ensure NULL parameters are ignored. */
207 uid_t uid
= (uid_t
) -1;
208 char const *diag
= parse_user_spec ("", &uid
, NULL
, NULL
, NULL
);
211 printf ("unexpected error: %s\n", diag
);
221 indent-tabs-mode: nil