]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - contrib/cpio/src/userspec.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / contrib / cpio / src / userspec.c
1 /* $FreeBSD$ */
2
3 /* userspec.c -- Parse a user and group string.
4    Copyright (C) 1989, 1990, 1991, 1992, 2001, 
5    2004, 2005 Free Software Foundation, Inc.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2, or (at your option)
10    any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public
18    License along with this program; if not, write to the Free
19    Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20    Boston, MA 02110-1301 USA.  */
21
22 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.  */
23 \f
24 #include <system.h>
25
26 #ifdef __GNUC__
27 #define alloca __builtin_alloca
28 #else
29 #ifdef HAVE_ALLOCA_H
30 #include <alloca.h>
31 #else
32 #ifdef _AIX
33  #pragma alloca
34 #else
35 char *alloca ();
36 #endif
37 #endif
38 #endif
39
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <sys/types.h>
43 #include <pwd.h>
44 #include <grp.h>
45
46 #if !HAVE_DECL_GETPWNAM
47 extern struct passwd *getpwnam (const char *name);
48 #endif
49 #if !HAVE_DECL_GETGRNAM
50 extern struct group *getgrnam (const char *name);
51 #endif
52 #if !HAVE_DECL_GETGRGID
53 extern struct group *getgrgid (gid_t gid);
54 #endif
55
56 #ifndef HAVE_ENDPWENT
57 # define endpwent()
58 #endif
59 #ifndef HAVE_ENDGRENT
60 # define endgrent()
61 #endif
62
63 /* Perform the equivalent of the statement `dest = strdup (src);',
64    but obtaining storage via alloca instead of from the heap.  */
65
66 #define V_STRDUP(dest, src)                                             \
67   do                                                                    \
68     {                                                                   \
69       int _len = strlen ((src));                                        \
70       (dest) = (char *) alloca (_len + 1);                              \
71       strcpy (dest, src);                                               \
72     }                                                                   \
73   while (0)
74
75 /* Return nonzero if STR represents an unsigned decimal integer,
76    otherwise return 0. */
77
78 static int
79 isnumber_p (const char *str)
80 {
81   for (; *str; str++)
82     if (!isdigit (*str))
83       return 0;
84   return 1;
85 }
86
87 /* Extract from NAME, which has the form "[user][:.][group]",
88    a USERNAME, UID U, GROUPNAME, and GID G.
89    Either user or group, or both, must be present.
90    If the group is omitted but the ":" or "." separator is given,
91    use the given user's login group.
92
93    USERNAME and GROUPNAME will be in newly malloc'd memory.
94    Either one might be NULL instead, indicating that it was not
95    given and the corresponding numeric ID was left unchanged.
96
97    Return NULL if successful, a static error message string if not.  */
98
99 const char *
100 parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
101                  char **username_arg, char **groupname_arg)
102 {
103   static const char *tired = "virtual memory exhausted";
104   const char *error_msg;
105   char *spec;                   /* A copy we can write on.  */
106   struct passwd *pwd;
107   struct group *grp;
108   char *g, *u, *separator;
109   char *groupname;
110
111   error_msg = NULL;
112   *username_arg = *groupname_arg = NULL;
113   groupname = NULL;
114
115   V_STRDUP (spec, spec_arg);
116
117   /* Find the separator if there is one.  */
118   separator = strchr (spec, ':');
119   if (separator == NULL)
120     separator = strchr (spec, '.');
121
122   /* Replace separator with a NUL.  */
123   if (separator != NULL)
124     *separator = '\0';
125
126   /* Set U and G to non-zero length strings corresponding to user and
127      group specifiers or to NULL.  */
128   u = (*spec == '\0' ? NULL : spec);
129
130   g = (separator == NULL || *(separator + 1) == '\0'
131        ? NULL
132        : separator + 1);
133
134   if (u == NULL && g == NULL)
135     return "can not omit both user and group";
136
137   if (u != NULL)
138     {
139       pwd = getpwnam (u);
140       if (pwd == NULL)
141         {
142
143           if (!isnumber_p (u))
144             error_msg = _("invalid user");
145           else
146             {
147               int use_login_group;
148               use_login_group = (separator != NULL && g == NULL);
149               if (use_login_group)
150                 error_msg = _("cannot get the login group of a numeric UID");
151               else
152                 *uid = atoi (u);
153             }
154         }
155       else
156         {
157           *uid = pwd->pw_uid;
158           if (g == NULL && separator != NULL)
159             {
160               /* A separator was given, but a group was not specified,
161                  so get the login group.  */
162               *gid = pwd->pw_gid;
163               grp = getgrgid (pwd->pw_gid);
164               if (grp == NULL)
165                 {
166                   /* This is enough room to hold the unsigned decimal
167                      representation of any 32-bit quantity and the trailing
168                      zero byte.  */
169                   char uint_buf[21];
170                   sprintf (uint_buf, "%u", (unsigned) (pwd->pw_gid));
171                   V_STRDUP (groupname, uint_buf);
172                 }
173               else
174                 {
175                   V_STRDUP (groupname, grp->gr_name);
176                 }
177               endgrent ();
178             }
179         }
180       endpwent ();
181     }
182
183   if (g != NULL && error_msg == NULL)
184     {
185       /* Explicit group.  */
186       grp = getgrnam (g);
187       if (grp == NULL)
188         {
189           if (!isnumber_p (g))
190             error_msg = _("invalid group");
191           else
192             *gid = atoi (g);
193         }
194       else
195         *gid = grp->gr_gid;
196       endgrent ();              /* Save a file descriptor.  */
197
198       if (error_msg == NULL)
199         V_STRDUP (groupname, g);
200     }
201
202   if (error_msg == NULL)
203     {
204       if (u != NULL)
205         {
206           *username_arg = strdup (u);
207           if (*username_arg == NULL)
208             error_msg = tired;
209         }
210
211       if (groupname != NULL && error_msg == NULL)
212         {
213           *groupname_arg = strdup (groupname);
214           if (*groupname_arg == NULL)
215             {
216               if (*username_arg != NULL)
217                 {
218                   free (*username_arg);
219                   *username_arg = NULL;
220                 }
221               error_msg = tired;
222             }
223         }
224     }
225
226   return error_msg;
227 }
228
229 #ifdef TEST
230
231 #define NULL_CHECK(s) ((s) == NULL ? "(null)" : (s))
232
233 int
234 main (int argc, char **argv)
235 {
236   int i;
237
238   for (i = 1; i < argc; i++)
239     {
240       const char *e;
241       char *username, *groupname;
242       uid_t uid;
243       gid_t gid;
244       char *tmp;
245
246       tmp = strdup (argv[i]);
247       e = parse_user_spec (tmp, &uid, &gid, &username, &groupname);
248       free (tmp);
249       printf ("%s: %u %u %s %s %s\n",
250               argv[i],
251               (unsigned int) uid,
252               (unsigned int) gid,
253               NULL_CHECK (username),
254               NULL_CHECK (groupname),
255               NULL_CHECK (e));
256     }
257
258   exit (0);
259 }
260
261 #endif