source: rtems/cpukit/libcsupport/src/pwdgrp.c @ 5eb27ce

4.115
Last change on this file since 5eb27ce was 5eb27ce, checked in by Nick Withers <nick.withers@…>, on 02/20/15 at 04:00:47

Don't fail to create passwd and group files if /etc already exists

  • 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  /*
65   * Do the best to create this directory.
66   */
67  mkdir("/etc", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
68
69  /*
70   *  Initialize /etc/passwd
71   */
72  init_file("/etc/passwd", "root::0:0::::\n");
73
74  /*
75   *  Initialize /etc/group
76   */
77  init_file("/etc/group", "root::0:\n");
78}
79
80void _libcsupport_pwdgrp_init(void)
81{
82  pthread_once(&pwdgrp_once, pwdgrp_init);
83}
84
85/**
86 *  Extract a string value from the database
87 */
88static int
89scanString(FILE *fp, char **name, char **bufp, size_t *nleft, int nlFlag)
90{
91  int c;
92
93  *name = *bufp;
94  for (;;) {
95    c = getc(fp);
96    if (c == ':') {
97        if (nlFlag)
98            return 0;
99        break;
100    }
101    if (c == '\n') {
102        if (!nlFlag)
103            return 0;
104        break;
105    }
106    if (c == EOF)
107      return 0;
108    if (*nleft < 2)
109      return 0;
110    **bufp = c;
111    ++(*bufp);
112    --(*nleft);
113  }
114  **bufp = '\0';
115  ++(*bufp);
116  --(*nleft);
117  return 1;
118}
119
120/**
121 *  Extract an integer value from the database
122 */
123static int
124scanInt(FILE *fp, int *val)
125{
126  int c;
127  unsigned int i = 0;
128  unsigned int limit = INT_MAX;
129  int sign = 0;
130  int d;
131
132  for (;;) {
133    c = getc(fp);
134    if (c == ':')
135      break;
136    if (sign == 0) {
137      if (c == '-') {
138        sign = -1;
139        limit++;
140        continue;
141      }
142      sign = 1;
143    }
144    if (!isdigit(c))
145      return 0;
146    d = c - '0';
147    if ((i > (limit / 10))
148     || ((i == (limit / 10)) && (d > (limit % 10))))
149      return 0;
150    i = i * 10 + d;
151  }
152  if (sign == 0)
153    return 0;
154  *val = i * sign;
155  return 1;
156}
157
158/*
159 * Extract a single password record from the database
160 */
161int _libcsupport_scanpw(
162  FILE *fp,
163  struct passwd *pwd,
164  char *buffer,
165  size_t bufsize
166)
167{
168  int pwuid, pwgid;
169
170  if (!scanString(fp, &pwd->pw_name, &buffer, &bufsize, 0)
171   || !scanString(fp, &pwd->pw_passwd, &buffer, &bufsize, 0)
172   || !scanInt(fp, &pwuid)
173   || !scanInt(fp, &pwgid)
174   || !scanString(fp, &pwd->pw_comment, &buffer, &bufsize, 0)
175   || !scanString(fp, &pwd->pw_gecos, &buffer, &bufsize, 0)
176   || !scanString(fp, &pwd->pw_dir, &buffer, &bufsize, 0)
177   || !scanString(fp, &pwd->pw_shell, &buffer, &bufsize, 1))
178    return 0;
179  pwd->pw_uid = pwuid;
180  pwd->pw_gid = pwgid;
181  return 1;
182}
183
184static int getpw_r(
185  const char     *name,
186  int             uid,
187  struct passwd  *pwd,
188  char           *buffer,
189  size_t          bufsize,
190  struct passwd **result
191)
192{
193  FILE *fp;
194  int match;
195
196  _libcsupport_pwdgrp_init();
197
198  if ((fp = fopen("/etc/passwd", "r")) == NULL)
199    rtems_set_errno_and_return_minus_one( EINVAL );
200
201  for(;;) {
202    if (!_libcsupport_scanpw(fp, pwd, buffer, bufsize))
203      goto error_einval;
204
205    if (name) {
206      match = (strcmp(pwd->pw_name, name) == 0);
207    } else {
208      match = (pwd->pw_uid == uid);
209    }
210
211    if (match) {
212      fclose(fp);
213      *result = pwd;
214      return 0;
215    }
216  }
217error_einval:
218  fclose(fp);
219  rtems_set_errno_and_return_minus_one( EINVAL );
220}
221
222int getpwnam_r(
223  const char     *name,
224  struct passwd  *pwd,
225  char           *buffer,
226  size_t          bufsize,
227  struct passwd **result
228)
229{
230  return getpw_r(name, 0, pwd, buffer, bufsize, result);
231}
232
233int getpwuid_r(
234  uid_t           uid,
235  struct passwd  *pwd,
236  char           *buffer,
237  size_t          bufsize,
238  struct passwd **result
239)
240{
241  return getpw_r(NULL, uid, pwd, buffer, bufsize, result);
242}
243
244/**
245 *  Extract a single group record from the database
246 */
247int _libcsupport_scangr(
248  FILE *fp,
249  struct group *grp,
250  char *buffer,
251  size_t bufsize
252)
253{
254  int grgid;
255  char *grmem, *cp;
256  int memcount;
257
258  if (!scanString(fp, &grp->gr_name, &buffer, &bufsize, 0)
259   || !scanString(fp, &grp->gr_passwd, &buffer, &bufsize, 0)
260   || !scanInt(fp, &grgid)
261   || !scanString(fp, &grmem, &buffer, &bufsize, 1))
262    return 0;
263  grp->gr_gid = grgid;
264
265  /*
266   * Determine number of members
267   */
268  if (grmem[0] == '\0') {
269    memcount = 0;
270  } else {
271    for (cp = grmem, memcount = 1 ; *cp != 0 ; cp++) {
272      if(*cp == ',')
273        memcount++;
274    }
275  }
276
277  /*
278   * Hack to produce (hopefully) a suitably-aligned array of pointers
279   */
280  if (bufsize < (((memcount+1)*sizeof(char *)) + 15))
281    return 0;
282  grp->gr_mem = (char **)(((uintptr_t)buffer + 15) & ~15);
283
284  /*
285   * Fill in pointer array
286   */
287  if (grmem[0] == '\0') {
288    memcount = 0;
289  } else {
290    grp->gr_mem[0] = grmem;
291    for (cp = grmem, memcount = 1 ; *cp != 0 ; cp++) {
292      if(*cp == ',') {
293        *cp = '\0';
294        grp->gr_mem[memcount++] = cp + 1;
295      }
296    }
297  }
298
299  grp->gr_mem[memcount] = NULL;
300  return 1;
301}
302
303static int getgr_r(
304  const char     *name,
305  int             gid,
306  struct group   *grp,
307  char           *buffer,
308  size_t          bufsize,
309  struct group  **result
310)
311{
312  FILE *fp;
313  int match;
314
315  _libcsupport_pwdgrp_init();
316
317  if ((fp = fopen("/etc/group", "r")) == NULL)
318    rtems_set_errno_and_return_minus_one( EINVAL );
319
320  for(;;) {
321    if (!_libcsupport_scangr(fp, grp, buffer, bufsize))
322      goto error_einval;
323
324    if (name) {
325      match = (strcmp(grp->gr_name, name) == 0);
326    } else {
327      match = (grp->gr_gid == gid);
328    }
329
330    if (match) {
331      fclose(fp);
332      *result = grp;
333      return 0;
334    }
335  }
336error_einval:
337  fclose(fp);
338  rtems_set_errno_and_return_minus_one( EINVAL );
339}
340
341int getgrnam_r(
342  const char     *name,
343  struct group   *grp,
344  char           *buffer,
345  size_t          bufsize,
346  struct group  **result
347)
348{
349  return getgr_r(name, 0, grp, buffer, bufsize, result);
350}
351
352int getgrgid_r(
353  gid_t           gid,
354  struct group   *grp,
355  char           *buffer,
356  size_t          bufsize,
357  struct group  **result
358)
359{
360  return getgr_r(NULL, gid, grp, buffer, bufsize, result);
361}
Note: See TracBrowser for help on using the repository browser.