source: rtems/cpukit/libcsupport/src/pwdgrp.c @ 3211e8e

4.11
Last change on this file since 3211e8e was 3211e8e, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 24, 2014 at 8:18:16 PM

cpukit/libcsupport/src/pwdgrp.c: Check return value

Coverity Id 1255518. mkdir() could fail. Check return value and return
on failure. Behavior is similar to if open() failed while writing the
files.

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/**
2 *  @file
3 *
4 *  @brief User Database Access Routines
5 *  @ingroup libcsupport
6 */
7
8/*
9 *  Copyright (c) 1999-2009 Ralf Corsepius <corsepiu@faw.uni-ulm.de>
10 *  Copyright (c) 1999-2013 Joel Sherrill <joel.sherrill@OARcorp.com>
11 *  Copyright (c) 2000-2001 Fernando Ruiz Casas <fernando.ruiz@ctv.es>
12 *  Copyright (c) 2002 Eric Norum <eric.norum@usask.ca>
13 *  Copyright (c) 2003 Till Straumann <strauman@slac.stanford.edu>
14 *  Copyright (c) 2012 Alex Ivanov <alexivanov97@gmail.com>
15 *
16 *  The license and distribution terms for this file may be
17 *  found in the file LICENSE in this distribution or at
18 *  http://www.rtems.org/license/LICENSE.
19 */
20
21#if HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#include <sys/stat.h>
26#include <pwd.h>
27#include <grp.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <string.h>
33#include <limits.h>
34#include <ctype.h>
35#include <pthread.h>
36
37#include <rtems/seterr.h>
38
39#include "pwdgrp.h"
40
41static pthread_once_t pwdgrp_once = PTHREAD_ONCE_INIT;
42
43static void init_file(const char *name, const char *content)
44{
45  /*
46   * Unlike to standard UNIX systems, these files are only readable and
47   * writeable for the root user.  This way we avoid the need for an
48   * /etc/shadow.  In case more UNIX compatibility is desired, this can be
49   * added on demand.
50   */
51  int fd = open(name, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
52
53  if (fd >= 0) {
54    write(fd, content, strlen(content));
55    close(fd);
56  }
57}
58
59/**
60 *  Initialize useable but dummy databases
61 */
62static void pwdgrp_init(void)
63{
64  int rc;
65
66  rc = mkdir("/etc", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
67  if ( rc != 0 )
68    return;
69
70  /*
71   *  Initialize /etc/passwd
72   */
73  init_file("/etc/passwd", "root::0:0::::\n");
74
75  /*
76   *  Initialize /etc/group
77   */
78  init_file("/etc/group", "root::0:\n");
79}
80
81void _libcsupport_pwdgrp_init(void)
82{
83  pthread_once(&pwdgrp_once, pwdgrp_init);
84}
85
86/**
87 *  Extract a string value from the database
88 */
89static int
90scanString(FILE *fp, char **name, char **bufp, size_t *nleft, int nlFlag)
91{
92  int c;
93
94  *name = *bufp;
95  for (;;) {
96    c = getc(fp);
97    if (c == ':') {
98        if (nlFlag)
99            return 0;
100        break;
101    }
102    if (c == '\n') {
103        if (!nlFlag)
104            return 0;
105        break;
106    }
107    if (c == EOF)
108      return 0;
109    if (*nleft < 2)
110      return 0;
111    **bufp = c;
112    ++(*bufp);
113    --(*nleft);
114  }
115  **bufp = '\0';
116  ++(*bufp);
117  --(*nleft);
118  return 1;
119}
120
121/**
122 *  Extract an integer value from the database
123 */
124static int
125scanInt(FILE *fp, int *val)
126{
127  int c;
128  unsigned int i = 0;
129  unsigned int limit = INT_MAX;
130  int sign = 0;
131  int d;
132
133  for (;;) {
134    c = getc(fp);
135    if (c == ':')
136      break;
137    if (sign == 0) {
138      if (c == '-') {
139        sign = -1;
140        limit++;
141        continue;
142      }
143      sign = 1;
144    }
145    if (!isdigit(c))
146      return 0;
147    d = c - '0';
148    if ((i > (limit / 10))
149     || ((i == (limit / 10)) && (d > (limit % 10))))
150      return 0;
151    i = i * 10 + d;
152  }
153  if (sign == 0)
154    return 0;
155  *val = i * sign;
156  return 1;
157}
158
159/*
160 * Extract a single password record from the database
161 */
162int _libcsupport_scanpw(
163  FILE *fp,
164  struct passwd *pwd,
165  char *buffer,
166  size_t bufsize
167)
168{
169  int pwuid, pwgid;
170
171  if (!scanString(fp, &pwd->pw_name, &buffer, &bufsize, 0)
172   || !scanString(fp, &pwd->pw_passwd, &buffer, &bufsize, 0)
173   || !scanInt(fp, &pwuid)
174   || !scanInt(fp, &pwgid)
175   || !scanString(fp, &pwd->pw_comment, &buffer, &bufsize, 0)
176   || !scanString(fp, &pwd->pw_gecos, &buffer, &bufsize, 0)
177   || !scanString(fp, &pwd->pw_dir, &buffer, &bufsize, 0)
178   || !scanString(fp, &pwd->pw_shell, &buffer, &bufsize, 1))
179    return 0;
180  pwd->pw_uid = pwuid;
181  pwd->pw_gid = pwgid;
182  return 1;
183}
184
185static int getpw_r(
186  const char     *name,
187  int             uid,
188  struct passwd  *pwd,
189  char           *buffer,
190  size_t          bufsize,
191  struct passwd **result
192)
193{
194  FILE *fp;
195  int match;
196
197  _libcsupport_pwdgrp_init();
198
199  if ((fp = fopen("/etc/passwd", "r")) == NULL)
200    rtems_set_errno_and_return_minus_one( EINVAL );
201
202  for(;;) {
203    if (!_libcsupport_scanpw(fp, pwd, buffer, bufsize))
204      goto error_einval;
205
206    if (name) {
207      match = (strcmp(pwd->pw_name, name) == 0);
208    } else {
209      match = (pwd->pw_uid == uid);
210    }
211
212    if (match) {
213      fclose(fp);
214      *result = pwd;
215      return 0;
216    }
217  }
218error_einval:
219  fclose(fp);
220  rtems_set_errno_and_return_minus_one( EINVAL );
221}
222
223int getpwnam_r(
224  const char     *name,
225  struct passwd  *pwd,
226  char           *buffer,
227  size_t          bufsize,
228  struct passwd **result
229)
230{
231  return getpw_r(name, 0, pwd, buffer, bufsize, result);
232}
233
234int getpwuid_r(
235  uid_t           uid,
236  struct passwd  *pwd,
237  char           *buffer,
238  size_t          bufsize,
239  struct passwd **result
240)
241{
242  return getpw_r(NULL, uid, pwd, buffer, bufsize, result);
243}
244
245/**
246 *  Extract a single group record from the database
247 */
248int _libcsupport_scangr(
249  FILE *fp,
250  struct group *grp,
251  char *buffer,
252  size_t bufsize
253)
254{
255  int grgid;
256  char *grmem, *cp;
257  int memcount;
258
259  if (!scanString(fp, &grp->gr_name, &buffer, &bufsize, 0)
260   || !scanString(fp, &grp->gr_passwd, &buffer, &bufsize, 0)
261   || !scanInt(fp, &grgid)
262   || !scanString(fp, &grmem, &buffer, &bufsize, 1))
263    return 0;
264  grp->gr_gid = grgid;
265
266  /*
267   * Determine number of members
268   */
269  if (grmem[0] == '\0') {
270    memcount = 0;
271  } else {
272    for (cp = grmem, memcount = 1 ; *cp != 0 ; cp++) {
273      if(*cp == ',')
274        memcount++;
275    }
276  }
277
278  /*
279   * Hack to produce (hopefully) a suitably-aligned array of pointers
280   */
281  if (bufsize < (((memcount+1)*sizeof(char *)) + 15))
282    return 0;
283  grp->gr_mem = (char **)(((uintptr_t)buffer + 15) & ~15);
284
285  /*
286   * Fill in pointer array
287   */
288  if (grmem[0] == '\0') {
289    memcount = 0;
290  } else {
291    grp->gr_mem[0] = grmem;
292    for (cp = grmem, memcount = 1 ; *cp != 0 ; cp++) {
293      if(*cp == ',') {
294        *cp = '\0';
295        grp->gr_mem[memcount++] = cp + 1;
296      }
297    }
298  }
299
300  grp->gr_mem[memcount] = NULL;
301  return 1;
302}
303
304static int getgr_r(
305  const char     *name,
306  int             gid,
307  struct group   *grp,
308  char           *buffer,
309  size_t          bufsize,
310  struct group  **result
311)
312{
313  FILE *fp;
314  int match;
315
316  _libcsupport_pwdgrp_init();
317
318  if ((fp = fopen("/etc/group", "r")) == NULL)
319    rtems_set_errno_and_return_minus_one( EINVAL );
320
321  for(;;) {
322    if (!_libcsupport_scangr(fp, grp, buffer, bufsize))
323      goto error_einval;
324
325    if (name) {
326      match = (strcmp(grp->gr_name, name) == 0);
327    } else {
328      match = (grp->gr_gid == gid);
329    }
330
331    if (match) {
332      fclose(fp);
333      *result = grp;
334      return 0;
335    }
336  }
337error_einval:
338  fclose(fp);
339  rtems_set_errno_and_return_minus_one( EINVAL );
340}
341
342int getgrnam_r(
343  const char     *name,
344  struct group   *grp,
345  char           *buffer,
346  size_t          bufsize,
347  struct group  **result
348)
349{
350  return getgr_r(name, 0, grp, buffer, bufsize, result);
351}
352
353int getgrgid_r(
354  gid_t           gid,
355  struct group   *grp,
356  char           *buffer,
357  size_t          bufsize,
358  struct group  **result
359)
360{
361  return getgr_r(NULL, gid, grp, buffer, bufsize, result);
362}
Note: See TracBrowser for help on using the repository browser.