source: rtems/cpukit/libcsupport/src/pwdgrp.c @ e02d5dd9

4.115
Last change on this file since e02d5dd9 was e02d5dd9, checked in by Sebastian Huber <sebastian.huber@…>, on 11/17/14 at 12:35:58

Ensure security of default user environment

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