xref: /386bsd/usr/src/usr.bin/cpio/userspec.c (revision a2142627)
1 /* userspec.c -- Parse a user and group string.
2    Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17 
18 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.  */
19 
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <pwd.h>
23 #include <grp.h>
24 
25 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
26 #include <string.h>
27 #ifndef index
28 #define index strchr
29 #endif
30 #else
31 #include <strings.h>
32 #endif
33 
34 #ifdef STDC_HEADERS
35 #include <stdlib.h>
36 #else
37 char *malloc ();
38 #endif
39 
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 
44 #ifndef _POSIX_VERSION
45 struct passwd *getpwnam ();
46 struct group *getgrnam ();
47 struct group *getgrgid ();
48 #endif
49 
50 #ifdef _POSIX_SOURCE
51 #define endpwent()
52 #define endgrent()
53 #endif
54 
55 #define isdigit(c) ((c) >= '0' && (c) <= '9')
56 
57 char *strdup ();
58 static int isnumber ();
59 
60 /* Extract from NAME, which has the form "[user][:.][group]",
61    a USERNAME, UID U, GROUPNAME, and GID G.
62    Either user or group, or both, must be present.
63    If the group is omitted but the ":" or "." separator is given,
64    use the given user's login group.
65 
66    USERNAME and GROUPNAME will be in newly malloc'd memory.
67    Either one might be NULL instead, indicating that it was not
68    given and the corresponding numeric ID was left unchanged.
69    Might write NULs into NAME.
70 
71    Return NULL if successful, a static error message string if not.  */
72 
73 char *
parse_user_spec(name,uid,gid,username,groupname)74 parse_user_spec (name, uid, gid, username, groupname)
75      char *name;
76      uid_t *uid;
77      gid_t *gid;
78      char **username, **groupname;
79 {
80   static char *tired = "virtual memory exhausted";
81   struct passwd *pwd;
82   struct group *grp;
83   char *cp;
84   int use_login_group = 0;
85 
86   *username = *groupname = NULL;
87 
88   /* Check whether a group is given.  */
89   cp = index (name, ':');
90   if (cp == NULL)
91     cp = index (name, '.');
92   if (cp != NULL)
93     {
94       *cp++ = '\0';
95       if (*cp == '\0')
96 	{
97 	  if (cp == name + 1)
98 	    /* Neither user nor group given, just "." or ":".  */
99 	    return "can not omit both user and group";
100 	  else
101 	    /* "user.".  */
102 	    use_login_group = 1;
103 	}
104       else
105 	{
106 	  /* Explicit group.  */
107 	  *groupname = strdup (cp);
108 	  if (*groupname == NULL)
109 	    return tired;
110 	  grp = getgrnam (cp);
111 	  if (grp == NULL)
112 	    {
113 	      if (!isnumber (cp))
114 		return "invalid group";
115 	      *gid = atoi (cp);
116 	    }
117 	  else
118 	    *gid = grp->gr_gid;
119 	  endgrent ();		/* Save a file descriptor.  */
120 	}
121     }
122 
123   /* Parse the user name, now that any group has been removed.  */
124 
125   if (name[0] == '\0')
126     /* No user name was given, just a group.  */
127     return NULL;
128 
129   *username = strdup (name);
130   if (*username == NULL)
131     return tired;
132 
133   pwd = getpwnam (name);
134   if (pwd == NULL)
135     {
136       if (!isnumber (name))
137 	return "invalid user";
138       if (use_login_group)
139 	return "cannot get the login group of a numeric UID";
140       *uid = atoi (name);
141     }
142   else
143     {
144       *uid = pwd->pw_uid;
145       if (use_login_group)
146 	{
147 	  *gid = pwd->pw_gid;
148 	  grp = getgrgid (pwd->pw_gid);
149 	  if (grp == NULL)
150 	    {
151 	      *groupname = malloc (15);
152 	      if (*groupname == NULL)
153 		return tired;
154 	      sprintf (*groupname, "%u", pwd->pw_gid);
155 	    }
156 	  else
157 	    {
158 	      *groupname = strdup (grp->gr_name);
159 	      if (*groupname == NULL)
160 		return tired;
161 	    }
162 	  endgrent ();
163 	}
164     }
165   endpwent ();
166   return NULL;
167 }
168 
169 /* Return nonzero if STR represents an unsigned decimal integer,
170    otherwise return 0. */
171 
172 static int
isnumber(str)173 isnumber (str)
174      char *str;
175 {
176   for (; *str; str++)
177     if (!isdigit (*str))
178       return 0;
179   return 1;
180 }
181