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