OpenCoverage

userspec.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/coreutils/src/gnulib/lib/userspec.c
Source codeSwitch to Preprocessed file
LineSourceCount
1/* userspec.c -- Parse a user and group string.-
2 Copyright (C) 1989-1992, 1997-1998, 2000, 2002-2018 Free Software-
3 Foundation, Inc.-
4-
5 This program is free software: you can redistribute it and/or modify-
6 it under the terms of the GNU General Public License as published by-
7 the Free Software Foundation; either version 3 of the License, or-
8 (at your option) any later version.-
9-
10 This program is distributed in the hope that it will be useful,-
11 but WITHOUT ANY WARRANTY; without even the implied warranty of-
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-
13 GNU General Public License for more details.-
14-
15 You should have received a copy of the GNU General Public License-
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */-
17-
18/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */-
19-
20#include <config.h>-
21-
22/* Specification. */-
23#include "userspec.h"-
24-
25#include <stdbool.h>-
26#include <stdio.h>-
27#include <sys/types.h>-
28#include <pwd.h>-
29#include <grp.h>-
30-
31#if HAVE_SYS_PARAM_H-
32# include <sys/param.h>-
33#endif-
34-
35#include <limits.h>-
36#include <stdlib.h>-
37#include <string.h>-
38-
39#include <unistd.h>-
40-
41#include "intprops.h"-
42#include "inttostr.h"-
43#include "xalloc.h"-
44#include "xstrtol.h"-
45-
46#include "gettext.h"-
47#define _(msgid) gettext (msgid)-
48#define N_(msgid) msgid-
49-
50#ifndef HAVE_ENDGRENT-
51# define endgrent() ((void) 0)-
52#endif-
53-
54#ifndef HAVE_ENDPWENT-
55# define endpwent() ((void) 0)-
56#endif-
57-
58#ifndef UID_T_MAX-
59# define UID_T_MAX TYPE_MAXIMUM (uid_t)-
60#endif-
61-
62#ifndef GID_T_MAX-
63# define GID_T_MAX TYPE_MAXIMUM (gid_t)-
64#endif-
65-
66/* MAXUID may come from limits.h or sys/params.h. */-
67#ifndef MAXUID-
68# define MAXUID UID_T_MAX-
69#endif-
70#ifndef MAXGID-
71# define MAXGID GID_T_MAX-
72#endif-
73-
74#ifdef __DJGPP__-
75-
76/* ISDIGIT differs from isdigit, as follows:-
77 - Its arg may be any int or unsigned int; it need not be an unsigned char-
78 or EOF.-
79 - It's typically faster.-
80 POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to-
81 isdigit unless it's important to use the locale's definition-
82 of "digit" even when the host does not conform to POSIX. */-
83# define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)-
84-
85/* Return true if STR represents an unsigned decimal integer. */-
86-
87static bool-
88is_number (const char *str)-
89{-
90 do-
91 {-
92 if (!ISDIGIT (*str))-
93 return false;-
94 }-
95 while (*++str);-
96-
97 return true;-
98}-
99#endif-
100-
101static char const *-
102parse_with_separator (char const *spec, char const *separator,-
103 uid_t *uid, gid_t *gid,-
104 char **username, char **groupname)-
105{-
106 static const char *E_invalid_user = N_("invalid user");-
107 static const char *E_invalid_group = N_("invalid group");-
108 static const char *E_bad_spec = N_("invalid spec");-
109-
110 const char *error_msg;-
111 struct passwd *pwd;-
112 struct group *grp;-
113 char *u;-
114 char const *g;-
115 char *gname = NULL;-
116 uid_t unum = *uid;-
117 gid_t gnum = gid ? *gid : -1;
gidDescription
TRUEevaluated 44 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 113 times by 1 test
Evaluated by:
  • id
44-113
118-
119 error_msg = NULL;-
120 if (username)
usernameDescription
TRUEevaluated 38 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 119 times by 2 tests
Evaluated by:
  • chown
  • id
38-119
121 *username = NULL;
executed 38 times by 1 test: *username = ((void *)0) ;
Executed by:
  • chown
38
122 if (groupname)
groupnameDescription
TRUEevaluated 38 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 119 times by 2 tests
Evaluated by:
  • chown
  • id
38-119
123 *groupname = NULL;
executed 38 times by 1 test: *groupname = ((void *)0) ;
Executed by:
  • chown
38
124-
125 /* Set U and G to nonzero length strings corresponding to user and-
126 group specifiers or to NULL. If U is not NULL, it is a newly-
127 allocated string. */-
128-
129 u = NULL;-
130 if (separator == NULL)
separator == ((void *)0)Description
TRUEevaluated 128 times by 2 tests
Evaluated by:
  • chown
  • id
FALSEevaluated 29 times by 1 test
Evaluated by:
  • chown
29-128
131 {-
132 if (*spec)
*specDescription
TRUEevaluated 127 times by 2 tests
Evaluated by:
  • chown
  • id
FALSEevaluated 1 time by 1 test
Evaluated by:
  • chown
1-127
133 u = xstrdup (spec);
executed 127 times by 2 tests: u = xstrdup (spec);
Executed by:
  • chown
  • id
127
134 }
executed 128 times by 2 tests: end of block
Executed by:
  • chown
  • id
128
135 else-
136 {-
137 size_t ulen = separator - spec;-
138 if (ulen != 0)
ulen != 0Description
TRUEevaluated 13 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 16 times by 1 test
Evaluated by:
  • chown
13-16
139 {-
140 u = xmemdup (spec, ulen + 1);-
141 u[ulen] = '\0';-
142 }
executed 13 times by 1 test: end of block
Executed by:
  • chown
13
143 }
executed 29 times by 1 test: end of block
Executed by:
  • chown
29
144-
145 g = (separator == NULL || *(separator + 1) == '\0'
separator == ((void *)0)Description
TRUEevaluated 128 times by 2 tests
Evaluated by:
  • chown
  • id
FALSEevaluated 29 times by 1 test
Evaluated by:
  • chown
*(separator + 1) == '\0'Description
TRUEevaluated 6 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 23 times by 1 test
Evaluated by:
  • chown
6-128
146 ? NULL-
147 : separator + 1);-
148-
149#ifdef __DJGPP__-
150 /* Pretend that we are the user U whose group is G. This makes-
151 pwd and grp functions "know" about the UID and GID of these. */-
152 if (u && !is_number (u))-
153 setenv ("USER", u, 1);-
154 if (g && !is_number (g))-
155 setenv ("GROUP", g, 1);-
156#endif-
157-
158 if (u != NULL)
u != ((void *)0)Description
TRUEevaluated 140 times by 2 tests
Evaluated by:
  • chown
  • id
FALSEevaluated 17 times by 1 test
Evaluated by:
  • chown
17-140
159 {-
160 /* If it starts with "+", skip the look-up. */-
161 pwd = (*u == '+' ? NULL : getpwnam (u));
*u == '+'Description
TRUEevaluated 3 times by 1 test
Evaluated by:
  • id
FALSEevaluated 137 times by 2 tests
Evaluated by:
  • chown
  • id
3-137
162 if (pwd == NULL)
pwd == ((void *)0)Description
TRUEevaluated 28 times by 2 tests
Evaluated by:
  • chown
  • id
FALSEevaluated 112 times by 2 tests
Evaluated by:
  • chown
  • id
28-112
163 {-
164 bool use_login_group = (separator != NULL && g == NULL);
separator != ((void *)0)Description
TRUEevaluated 7 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 21 times by 2 tests
Evaluated by:
  • chown
  • id
g == ((void *)0)Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 5 times by 1 test
Evaluated by:
  • chown
2-21
165 if (use_login_group)
use_login_groupDescription
TRUEevaluated 2 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 26 times by 2 tests
Evaluated by:
  • chown
  • id
2-26
166 {-
167 /* If there is no group,-
168 then there may not be a trailing ":", either. */-
169 error_msg = E_bad_spec;-
170 }
executed 2 times by 1 test: end of block
Executed by:
  • chown
2
171 else-
172 {-
173 unsigned long int tmp;-
174 if (xstrtoul (u, NULL, 10, &tmp, "") == LONGINT_OK
xstrtoul (u, (... == LONGINT_OKDescription
TRUEevaluated 14 times by 2 tests
Evaluated by:
  • chown
  • id
FALSEevaluated 12 times by 2 tests
Evaluated by:
  • chown
  • id
12-14
175 && tmp <= MAXUID && (uid_t) tmp != (uid_t) -1)
tmp <= ((uid_t... 1) * 2 + 1)))Description
TRUEevaluated 14 times by 2 tests
Evaluated by:
  • chown
  • id
FALSEnever evaluated
(uid_t) tmp != (uid_t) -1Description
TRUEevaluated 14 times by 2 tests
Evaluated by:
  • chown
  • id
FALSEnever evaluated
0-14
176 unum = tmp;
executed 14 times by 2 tests: unum = tmp;
Executed by:
  • chown
  • id
14
177 else-
178 error_msg = E_invalid_user;
executed 12 times by 2 tests: error_msg = E_invalid_user;
Executed by:
  • chown
  • id
12
179 }-
180 }-
181 else-
182 {-
183 unum = pwd->pw_uid;-
184 if (g == NULL && separator != NULL)
g == ((void *)0)Description
TRUEevaluated 108 times by 2 tests
Evaluated by:
  • chown
  • id
FALSEevaluated 4 times by 1 test
Evaluated by:
  • chown
separator != ((void *)0)Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 106 times by 2 tests
Evaluated by:
  • chown
  • id
2-108
185 {-
186 /* A separator was given, but a group was not specified,-
187 so get the login group. */-
188 char buf[INT_BUFSIZE_BOUND (uintmax_t)];-
189 gnum = pwd->pw_gid;-
190 grp = getgrgid (gnum);-
191 gname = xstrdup (grp ? grp->gr_name : umaxtostr (gnum, buf));-
192 endgrent ();-
193 }
executed 2 times by 1 test: end of block
Executed by:
  • chown
2
194 }
executed 112 times by 2 tests: end of block
Executed by:
  • chown
  • id
112
195 endpwent ();-
196 }
executed 140 times by 2 tests: end of block
Executed by:
  • chown
  • id
140
197-
198 if (g != NULL && error_msg == NULL)
g != ((void *)0)Description
TRUEevaluated 23 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 134 times by 2 tests
Evaluated by:
  • chown
  • id
error_msg == ((void *)0)Description
TRUEevaluated 23 times by 1 test
Evaluated by:
  • chown
FALSEnever evaluated
0-134
199 {-
200 /* Explicit group. */-
201 /* If it starts with "+", skip the look-up. */-
202 grp = (*g == '+' ? NULL : getgrnam (g));
*g == '+'Description
TRUEnever evaluated
FALSEevaluated 23 times by 1 test
Evaluated by:
  • chown
0-23
203 if (grp == NULL)
grp == ((void *)0)Description
TRUEevaluated 17 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 6 times by 1 test
Evaluated by:
  • chown
6-17
204 {-
205 unsigned long int tmp;-
206 if (xstrtoul (g, NULL, 10, &tmp, "") == LONGINT_OK
xstrtoul (g, (... == LONGINT_OKDescription
TRUEevaluated 17 times by 1 test
Evaluated by:
  • chown
FALSEnever evaluated
0-17
207 && tmp <= MAXGID && (gid_t) tmp != (gid_t) -1)
tmp <= ((gid_t... 1) * 2 + 1)))Description
TRUEevaluated 17 times by 1 test
Evaluated by:
  • chown
FALSEnever evaluated
(gid_t) tmp != (gid_t) -1Description
TRUEevaluated 17 times by 1 test
Evaluated by:
  • chown
FALSEnever evaluated
0-17
208 gnum = tmp;
executed 17 times by 1 test: gnum = tmp;
Executed by:
  • chown
17
209 else-
210 error_msg = E_invalid_group;
never executed: error_msg = E_invalid_group;
0
211 }-
212 else-
213 gnum = grp->gr_gid;
executed 6 times by 1 test: gnum = grp->gr_gid;
Executed by:
  • chown
6
214 endgrent (); /* Save a file descriptor. */-
215 gname = xstrdup (g);-
216 }
executed 23 times by 1 test: end of block
Executed by:
  • chown
23
217-
218 if (error_msg == NULL)
error_msg == ((void *)0)Description
TRUEevaluated 143 times by 2 tests
Evaluated by:
  • chown
  • id
FALSEevaluated 14 times by 2 tests
Evaluated by:
  • chown
  • id
14-143
219 {-
220 *uid = unum;-
221 if (gid)
gidDescription
TRUEevaluated 32 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 111 times by 1 test
Evaluated by:
  • id
32-111
222 *gid = gnum;
executed 32 times by 1 test: *gid = gnum;
Executed by:
  • chown
32
223 if (username)
usernameDescription
TRUEevaluated 27 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 116 times by 2 tests
Evaluated by:
  • chown
  • id
27-116
224 {-
225 *username = u;-
226 u = NULL;-
227 }
executed 27 times by 1 test: end of block
Executed by:
  • chown
27
228 if (groupname)
groupnameDescription
TRUEevaluated 27 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 116 times by 2 tests
Evaluated by:
  • chown
  • id
27-116
229 {-
230 *groupname = gname;-
231 gname = NULL;-
232 }
executed 27 times by 1 test: end of block
Executed by:
  • chown
27
233 }
executed 143 times by 2 tests: end of block
Executed by:
  • chown
  • id
143
234-
235 free (u);-
236 free (gname);-
237 return error_msg ? _(error_msg) : NULL;
executed 157 times by 2 tests: return error_msg ? dcgettext (((void *)0), error_msg , 5) : ((void *)0) ;
Executed by:
  • chown
  • id
157
238}-
239-
240/* Extract from SPEC, which has the form "[user][:.][group]",-
241 a USERNAME, UID U, GROUPNAME, and GID G.-
242 If the GID parameter is NULL the entire SPEC is treated as a user.-
243 If the USERNAME and GROUPNAME parameters are NULL they're ignored.-
244 Either user or group, or both, must be present.-
245 If the group is omitted but the separator is given,-
246 use the given user's login group.-
247 If SPEC contains a ':', then use that as the separator, ignoring-
248 any '.'s. If there is no ':', but there is a '.', then first look-
249 up the entire SPEC as a login name. If that look-up fails, then-
250 try again interpreting the '.' as a separator.-
251-
252 USERNAME and GROUPNAME will be in newly malloc'd memory.-
253 Either one might be NULL instead, indicating that it was not-
254 given and the corresponding numeric ID was left unchanged.-
255-
256 Return NULL if successful, a static error message string if not. */-
257-
258char const *-
259parse_user_spec (char const *spec, uid_t *uid, gid_t *gid,-
260 char **username, char **groupname)-
261{-
262 char const *colon = gid ? strchr (spec, ':') : NULL;
gidDescription
TRUEevaluated 35 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 113 times by 1 test
Evaluated by:
  • id
__builtin_constant_p ( ':' )Description
TRUEevaluated 35 times by 1 test
Evaluated by:
  • chown
FALSEnever evaluated
!__builtin_constant_p ( spec )Description
TRUEevaluated 35 times by 1 test
Evaluated by:
  • chown
FALSEnever evaluated
( ':' ) == '\0'Description
TRUEnever evaluated
FALSEevaluated 35 times by 1 test
Evaluated by:
  • chown
0-113
263 char const *error_msg =-
264 parse_with_separator (spec, colon, uid, gid, username, groupname);-
265-
266 if (gid && !colon && error_msg)
gidDescription
TRUEevaluated 35 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 113 times by 1 test
Evaluated by:
  • id
!colonDescription
TRUEevaluated 15 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 20 times by 1 test
Evaluated by:
  • chown
error_msgDescription
TRUEevaluated 10 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 5 times by 1 test
Evaluated by:
  • chown
5-113
267 {-
268 /* If there's no colon but there is a dot, and if looking up the-
269 whole spec failed (i.e., the spec is not an owner name that-
270 includes a dot), then try again, but interpret the dot as a-
271 separator. This is a compatible extension to POSIX, since-
272 the POSIX-required behavior is always tried first. */-
273-
274 char const *dot = strchr (spec, '.');
__builtin_constant_p ( '.' )Description
TRUEevaluated 10 times by 1 test
Evaluated by:
  • chown
FALSEnever evaluated
!__builtin_constant_p ( spec )Description
TRUEevaluated 10 times by 1 test
Evaluated by:
  • chown
FALSEnever evaluated
( '.' ) == '\0'Description
TRUEnever evaluated
FALSEevaluated 10 times by 1 test
Evaluated by:
  • chown
0-10
275 if (dot
dotDescription
TRUEevaluated 9 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 1 time by 1 test
Evaluated by:
  • chown
1-9
276 && ! parse_with_separator (spec, dot, uid, gid, username, groupname))
! parse_with_s...me, groupname)Description
TRUEevaluated 8 times by 1 test
Evaluated by:
  • chown
FALSEevaluated 1 time by 1 test
Evaluated by:
  • chown
1-8
277 error_msg = NULL;
executed 8 times by 1 test: error_msg = ((void *)0) ;
Executed by:
  • chown
8
278 }
executed 10 times by 1 test: end of block
Executed by:
  • chown
10
279-
280 return error_msg;
executed 148 times by 2 tests: return error_msg;
Executed by:
  • chown
  • id
148
281}-
282-
283#ifdef TEST-
284-
285# define NULL_CHECK(s) ((s) == NULL ? "(null)" : (s))-
286-
287int-
288main (int argc, char **argv)-
289{-
290 int i;-
291-
292 for (i = 1; i < argc; i++)-
293 {-
294 const char *e;-
295 char *username, *groupname;-
296 uid_t uid;-
297 gid_t gid;-
298 char *tmp;-
299-
300 tmp = strdup (argv[i]);-
301 e = parse_user_spec (tmp, &uid, &gid, &username, &groupname);-
302 free (tmp);-
303 printf ("%s: %lu %lu %s %s %s\n",-
304 argv[i],-
305 (unsigned long int) uid,-
306 (unsigned long int) gid,-
307 NULL_CHECK (username),-
308 NULL_CHECK (groupname),-
309 NULL_CHECK (e));-
310 }-
311-
312 exit (0);-
313}-
314-
315#endif-
316-
317/*-
318Local Variables:-
319indent-tabs-mode: nil-
320End:-
321*/-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.1.2