Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:15

0001 /**
0002  *  @file
0003  *
0004  *  @brief User Database Access Routines
0005  *  @ingroup libcsupport
0006  */
0007 
0008 /*
0009  *  Copyright (c) 1999-2009 Ralf Corsepius <corsepiu@faw.uni-ulm.de>
0010  *  Copyright (c) 1999-2013 Joel Sherrill <joel.sherrill@OARcorp.com>
0011  *  Copyright (c) 2000-2001 Fernando Ruiz Casas <fruizcasas@gmail.com>
0012  *  Copyright (c) 2002 Eric Norum <eric@norum.ca>
0013  *  Copyright (c) 2003 Till Straumann <strauman@slac.stanford.edu>
0014  *  Copyright (c) 2012 Alex Ivanov <alexivanov97@gmail.com>
0015  *
0016  *  The license and distribution terms for this file may be
0017  *  found in the file LICENSE in this distribution or at
0018  *  http://www.rtems.org/license/LICENSE.
0019  */
0020 
0021 #ifdef HAVE_CONFIG_H
0022 #include "config.h"
0023 #endif
0024 
0025 #include <sys/stat.h>
0026 #include <pwd.h>
0027 #include <grp.h>
0028 #include <errno.h>
0029 #include <fcntl.h>
0030 #include <unistd.h>
0031 #include <stdlib.h>
0032 #include <string.h>
0033 #include <limits.h>
0034 #include <ctype.h>
0035 #include <pthread.h>
0036 #include <stdint.h>
0037 
0038 #include <rtems/seterr.h>
0039 #include <rtems/score/assert.h>
0040 
0041 #include "pwdgrp.h"
0042 
0043 static pthread_once_t pwdgrp_once = PTHREAD_ONCE_INIT;
0044 
0045 static void init_file(const char *name, const char *content)
0046 {
0047   /*
0048    * Unlike to standard UNIX systems, these files are only readable and
0049    * writeable for the root user.  This way we avoid the need for an
0050    * /etc/shadow.  In case more UNIX compatibility is desired, this can be
0051    * added on demand.
0052    */
0053   int fd = open(name, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
0054 
0055   if (fd >= 0) {
0056     write(fd, content, strlen(content));
0057     close(fd);
0058   }
0059 }
0060 
0061 /**
0062  *  Initialize useable but dummy databases
0063  */
0064 static void pwdgrp_init(void)
0065 {
0066   /*
0067    * Do the best to create this directory.
0068    *
0069    * /etc could be created by the network stack initialization or an initial
0070    * filesystem image. Deliberately ignore the return value.
0071    */
0072   (void) mkdir("/etc", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
0073 
0074   /*
0075    *  Initialize /etc/passwd
0076    */
0077   init_file("/etc/passwd", "root::0:0::::\n");
0078 
0079   /*
0080    *  Initialize /etc/group
0081    */
0082   init_file("/etc/group", "root::0:\n");
0083 }
0084 
0085 void _libcsupport_pwdgrp_init(void)
0086 {
0087   pthread_once(&pwdgrp_once, pwdgrp_init);
0088 }
0089 
0090 /**
0091  *  Extract a string value from the database
0092  */
0093 static int
0094 scanString(FILE *fp, char **name, char **bufp, size_t *nleft, int nlFlag)
0095 {
0096   int c;
0097 
0098   *name = *bufp;
0099   for (;;) {
0100     c = getc(fp);
0101     if (c == ':') {
0102         if (nlFlag)
0103             return 0;
0104         break;
0105     }
0106     if (c == '\n') {
0107         if (!nlFlag)
0108             return 0;
0109         break;
0110     }
0111     if (c == EOF)
0112       return 0;
0113     if (*nleft < 2)
0114       return 0;
0115     **bufp = c;
0116     ++(*bufp);
0117     --(*nleft);
0118   }
0119   **bufp = '\0';
0120   ++(*bufp);
0121   --(*nleft);
0122   return 1;
0123 }
0124 
0125 /**
0126  *  Extract an integer value from the database
0127  */
0128 static int
0129 scanInt(FILE *fp, int *val)
0130 {
0131   int c;
0132   unsigned int i = 0;
0133   unsigned int limit = INT_MAX;
0134   int sign = 0;
0135   int d;
0136 
0137   for (;;) {
0138     c = getc(fp);
0139     if (c == ':')
0140       break;
0141     if (sign == 0) {
0142       if (c == '-') {
0143         sign = -1;
0144         limit++;
0145         continue;
0146       }
0147       sign = 1;
0148     }
0149     if (!isdigit(c))
0150       return 0;
0151     d = c - '0';
0152     if ((i > (limit / 10))
0153      || ((i == (limit / 10)) && (d > (limit % 10))))
0154       return 0;
0155     i = i * 10 + d;
0156   }
0157   if (sign == 0)
0158     return 0;
0159   *val = i * sign;
0160   return 1;
0161 }
0162 
0163 /*
0164  * Extract a single password record from the database
0165  */
0166 int _libcsupport_scanpw(
0167   FILE *fp,
0168   struct passwd *pwd,
0169   char *buffer,
0170   size_t bufsize
0171 )
0172 {
0173   int pwuid, pwgid;
0174 
0175   if (!scanString(fp, &pwd->pw_name, &buffer, &bufsize, 0)
0176    || !scanString(fp, &pwd->pw_passwd, &buffer, &bufsize, 0)
0177    || !scanInt(fp, &pwuid)
0178    || !scanInt(fp, &pwgid)
0179    || !scanString(fp, &pwd->pw_comment, &buffer, &bufsize, 0)
0180    || !scanString(fp, &pwd->pw_gecos, &buffer, &bufsize, 0)
0181    || !scanString(fp, &pwd->pw_dir, &buffer, &bufsize, 0)
0182    || !scanString(fp, &pwd->pw_shell, &buffer, &bufsize, 1))
0183     return 0;
0184   pwd->pw_uid = pwuid;
0185   pwd->pw_gid = pwgid;
0186   return 1;
0187 }
0188 
0189 static int getpw_r(
0190   const char     *name,
0191   int             uid,
0192   struct passwd  *pwd,
0193   char           *buffer,
0194   size_t          bufsize,
0195   struct passwd **result
0196 )
0197 {
0198   FILE *fp;
0199   int match;
0200 
0201   _libcsupport_pwdgrp_init();
0202 
0203   if ((fp = fopen("/etc/passwd", "r")) == NULL)
0204     rtems_set_errno_and_return_minus_one( EINVAL );
0205 
0206   for(;;) {
0207     if (!_libcsupport_scanpw(fp, pwd, buffer, bufsize))
0208       goto error_einval;
0209 
0210     if (name) {
0211       match = (strcmp(pwd->pw_name, name) == 0);
0212     } else {
0213       match = (pwd->pw_uid == uid);
0214     }
0215 
0216     if (match) {
0217       fclose(fp);
0218       *result = pwd;
0219       return 0;
0220     }
0221   }
0222 error_einval:
0223   fclose(fp);
0224   rtems_set_errno_and_return_minus_one( EINVAL );
0225 }
0226 
0227 int getpwnam_r(
0228   const char     *name,
0229   struct passwd  *pwd,
0230   char           *buffer,
0231   size_t          bufsize,
0232   struct passwd **result
0233 )
0234 {
0235   return getpw_r(name, 0, pwd, buffer, bufsize, result);
0236 }
0237 
0238 int getpwuid_r(
0239   uid_t           uid,
0240   struct passwd  *pwd,
0241   char           *buffer,
0242   size_t          bufsize,
0243   struct passwd **result
0244 )
0245 {
0246   return getpw_r(NULL, uid, pwd, buffer, bufsize, result);
0247 }
0248 
0249 /**
0250  *  Extract a single group record from the database
0251  */
0252 int _libcsupport_scangr(
0253   FILE *fp,
0254   struct group *grp,
0255   char *buffer,
0256   size_t bufsize
0257 )
0258 {
0259   int grgid;
0260   char *grmem, *cp;
0261   int memcount;
0262 
0263   if (!scanString(fp, &grp->gr_name, &buffer, &bufsize, 0)
0264    || !scanString(fp, &grp->gr_passwd, &buffer, &bufsize, 0)
0265    || !scanInt(fp, &grgid)
0266    || !scanString(fp, &grmem, &buffer, &bufsize, 1))
0267     return 0;
0268   grp->gr_gid = grgid;
0269 
0270   /*
0271    * Determine number of members
0272    */
0273   if (grmem[0] == '\0') {
0274     memcount = 0;
0275   } else {
0276     for (cp = grmem, memcount = 1 ; *cp != 0 ; cp++) {
0277       if(*cp == ',')
0278         memcount++;
0279     }
0280   }
0281 
0282   /*
0283    * Hack to produce (hopefully) a suitably-aligned array of pointers
0284    */
0285   if (bufsize < (((memcount+1)*sizeof(char *)) + 15))
0286     return 0;
0287   grp->gr_mem = (char **)(((uintptr_t)buffer + 15) & ~15);
0288 
0289   /*
0290    * Fill in pointer array
0291    */
0292   if (grmem[0] == '\0') {
0293     memcount = 0;
0294   } else {
0295     grp->gr_mem[0] = grmem;
0296     for (cp = grmem, memcount = 1 ; *cp != 0 ; cp++) {
0297       if(*cp == ',') {
0298         *cp = '\0';
0299         grp->gr_mem[memcount++] = cp + 1;
0300       }
0301     }
0302   }
0303 
0304   grp->gr_mem[memcount] = NULL;
0305   return 1;
0306 }
0307 
0308 static int getgr_r(
0309   const char     *name,
0310   int             gid,
0311   struct group   *grp,
0312   char           *buffer,
0313   size_t          bufsize,
0314   struct group  **result
0315 )
0316 {
0317   FILE *fp;
0318   int match;
0319 
0320   _libcsupport_pwdgrp_init();
0321 
0322   if ((fp = fopen("/etc/group", "r")) == NULL)
0323     rtems_set_errno_and_return_minus_one( EINVAL );
0324 
0325   for(;;) {
0326     if (!_libcsupport_scangr(fp, grp, buffer, bufsize))
0327       goto error_einval;
0328 
0329     if (name) {
0330       match = (strcmp(grp->gr_name, name) == 0);
0331     } else {
0332       match = (grp->gr_gid == gid);
0333     }
0334 
0335     if (match) {
0336       fclose(fp);
0337       *result = grp;
0338       return 0;
0339     }
0340   }
0341 error_einval:
0342   fclose(fp);
0343   rtems_set_errno_and_return_minus_one( EINVAL );
0344 }
0345 
0346 int getgrnam_r(
0347   const char     *name,
0348   struct group   *grp,
0349   char           *buffer,
0350   size_t          bufsize,
0351   struct group  **result
0352 )
0353 {
0354   return getgr_r(name, 0, grp, buffer, bufsize, result);
0355 }
0356 
0357 int getgrgid_r(
0358   gid_t           gid,
0359   struct group   *grp,
0360   char           *buffer,
0361   size_t          bufsize,
0362   struct group  **result
0363 )
0364 {
0365   return getgr_r(NULL, gid, grp, buffer, bufsize, result);
0366 }