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

4.115
Last change on this file since 6935428 was 6935428, checked in by Sebastian Huber <sebastian.huber@…>, on 11/14/14 at 10:30:50

libcsupport: Avoid TOCTOU and format errors

  • Property mode set to 100644
File size: 6.7 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 <unistd.h>
30#include <stdlib.h>
31#include <string.h>
32#include <limits.h>
33#include <ctype.h>
34#include <pthread.h>
35
36#include <rtems/seterr.h>
37
38#include "pwdgrp.h"
39
40static pthread_once_t pwdgrp_once = PTHREAD_ONCE_INIT;
41
42static void init_file(const char *name, const char *content)
43{
44  FILE *fp = fopen(name, "wx");
45
46  if (fp != NULL) {
47    fputs(content, fp);
48    fclose(fp);
49  }
50}
51
52/**
53 *  Initialize useable but dummy databases
54 */
55static void pwdgrp_init(void)
56{
57  mkdir("/etc", 0777);
58
59  /*
60   *  Initialize /etc/passwd
61   */
62  init_file(
63    "/etc/passwd",
64    "root:*:0:0:root::/:/bin/sh\n"
65      "rtems:*:1:1:RTEMS Application::/:/bin/sh\n"
66      "tty:!:2:2:tty owner::/:/bin/false\n"
67  );
68
69  /*
70   *  Initialize /etc/group
71   */
72  init_file(
73    "/etc/group",
74    "root:x:0:root\n"
75      "rtems:x:1:rtems\n"
76      "tty:x:2:tty\n"
77  );
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  for (cp = grmem, memcount = 1 ; *cp != 0 ; cp++) {
269    if(*cp == ',')
270      memcount++;
271  }
272
273  /*
274   * Hack to produce (hopefully) a suitably-aligned array of pointers
275   */
276  if (bufsize < (((memcount+1)*sizeof(char *)) + 15))
277    return 0;
278  grp->gr_mem = (char **)(((uintptr_t)buffer + 15) & ~15);
279
280  /*
281   * Fill in pointer array
282   */
283  grp->gr_mem[0] = grmem;
284  for (cp = grmem, memcount = 1 ; *cp != 0 ; cp++) {
285    if(*cp == ',') {
286      *cp = '\0';
287      grp->gr_mem[memcount++] = cp + 1;
288    }
289  }
290  grp->gr_mem[memcount] = NULL;
291  return 1;
292}
293
294static int getgr_r(
295  const char     *name,
296  int             gid,
297  struct group   *grp,
298  char           *buffer,
299  size_t          bufsize,
300  struct group  **result
301)
302{
303  FILE *fp;
304  int match;
305
306  _libcsupport_pwdgrp_init();
307
308  if ((fp = fopen("/etc/group", "r")) == NULL)
309    rtems_set_errno_and_return_minus_one( EINVAL );
310
311  for(;;) {
312    if (!_libcsupport_scangr(fp, grp, buffer, bufsize))
313      goto error_einval;
314
315    if (name) {
316      match = (strcmp(grp->gr_name, name) == 0);
317    } else {
318      match = (grp->gr_gid == gid);
319    }
320
321    if (match) {
322      fclose(fp);
323      *result = grp;
324      return 0;
325    }
326  }
327error_einval:
328  fclose(fp);
329  rtems_set_errno_and_return_minus_one( EINVAL );
330}
331
332int getgrnam_r(
333  const char     *name,
334  struct group   *grp,
335  char           *buffer,
336  size_t          bufsize,
337  struct group  **result
338)
339{
340  return getgr_r(name, 0, grp, buffer, bufsize, result);
341}
342
343int getgrgid_r(
344  gid_t           gid,
345  struct group   *grp,
346  char           *buffer,
347  size_t          bufsize,
348  struct group  **result
349)
350{
351  return getgr_r(NULL, gid, grp, buffer, bufsize, result);
352}
Note: See TracBrowser for help on using the repository browser.