]> git.saurik.com Git - apple/system_cmds.git/blame_incremental - passwd.tproj/file_passwd.c
system_cmds-230.0.2.tar.gz
[apple/system_cmds.git] / passwd.tproj / file_passwd.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <pwd.h>
29#include <errno.h>
30#include "stringops.h"
31
32#define TEMP_FILE "/tmp/.pwtmp"
33
34#define _PASSWD_FILE "/etc/master.passwd"
35#define _COMPAT_FILE "/etc/passwd"
36#define _PASSWD_FIELDS 10
37#define BUFSIZE 8192
38
39extern void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
40
41static int do_compat = 1;
42
43char *
44getline(FILE *fp)
45{
46 static char s[BUFSIZE];
47 int len;
48
49 s[0] = '\0';
50
51 fgets(s, BUFSIZE, fp);
52 if (s == NULL || s[0] == '\0') return NULL;
53
54 if (s[0] == '#') return s;
55
56 len = strlen(s) - 1;
57 s[len] = '\0';
58
59 return s;
60}
61
62struct passwd *
63parse_user(char *line)
64{
65 static struct passwd pw = {0};
66 char **tokens;
67 int i, len;
68
69 if (pw.pw_name != NULL) free(pw.pw_name);
70 pw.pw_name = NULL;
71 if (pw.pw_passwd != NULL) free(pw.pw_passwd);
72 pw.pw_passwd = NULL;
73 if (pw.pw_gecos != NULL) free(pw.pw_gecos);
74 pw.pw_gecos = NULL;
75 if (pw.pw_dir != NULL) free(pw.pw_dir);
76 pw.pw_dir = NULL;
77 if (pw.pw_shell != NULL) free(pw.pw_shell);
78 pw.pw_shell = NULL;
79
80 if (pw.pw_class != NULL) free(pw.pw_class);
81 pw.pw_class = NULL;
82
83 if (line == NULL) return (struct passwd *)NULL;
84 tokens = explode(line, ':');
85 len = listLength(tokens);
86
87 if (len != _PASSWD_FIELDS)
88 {
89 freeList(tokens);
90 return (struct passwd *)NULL;
91 }
92
93 i = 0;
94 pw.pw_name = tokens[i++];
95 pw.pw_passwd = tokens[i++];
96 pw.pw_uid = atoi(tokens[i]);
97 free(tokens[i++]);
98 pw.pw_gid = atoi(tokens[i]);
99 free(tokens[i++]);
100 pw.pw_class = tokens[i++];
101 pw.pw_change = atoi(tokens[i]);
102 free(tokens[i++]);
103 pw.pw_expire = atoi(tokens[i]);
104 free(tokens[i++]);
105 pw.pw_gecos = tokens[i++];
106 pw.pw_dir = tokens[i++];
107 pw.pw_shell = tokens[i++];
108
109 return &pw;
110}
111
112struct passwd *
113find_user(char *uname, FILE *fp)
114{
115 char *line;
116 struct passwd *pw;
117
118 rewind(fp);
119
120 while (NULL != (line = getline(fp)))
121 {
122 if (line[0] == '#') continue;
123 pw = parse_user(line);
124 if (pw == (struct passwd *)NULL) continue;
125 if (!strcmp(uname, pw->pw_name)) return pw;
126 }
127
128 pw = parse_user(NULL);
129 return (struct passwd *)NULL;
130}
131
132void
133rewrite_file(char *pwname, FILE *fp, struct passwd *newpw)
134{
135 char *line;
136 struct passwd *pw;
137 FILE *tfp, *cfp;
138 char fname[256];
139
140 sprintf(fname, "%s.%d", TEMP_FILE, getpid());
141
142 tfp = fopen(fname, "w+");
143 if (tfp == NULL)
144 {
145 fprintf(stderr, "can't write temporary file \"%s\": ", fname);
146 perror("");
147 exit(1);
148 }
149
150 cfp = NULL;
151 if (!strcmp(pwname, _PASSWD_FILE))
152 {
153 cfp = fopen(_COMPAT_FILE, "w");
154 if (cfp == NULL)
155 {
156 fprintf(stderr, "warning: can't write compatability file \"%s\": ",
157 _COMPAT_FILE);
158 perror("");
159 }
160 }
161
162 if (cfp != NULL)
163 {
164 fprintf(cfp, "#\n");
165 fprintf(cfp, "# 4.3BSD-compatable User Database\n");
166 fprintf(cfp, "#\n");
167 fprintf(cfp, "# Note that this file is not consulted for login.\n");
168 fprintf(cfp, "# It only exisits for compatability with 4.3BSD utilities.\n");
169 fprintf(cfp, "#\n");
170 fprintf(cfp, "# This file is automatically re-written by various system utilities.\n");
171 fprintf(cfp, "# Do not edit this file. Changes will be lost.\n");
172 fprintf(cfp, "#\n");
173 }
174
175 rewind(fp);
176
177 while (NULL != (line = getline(fp)))
178 {
179 if (line[0] == '#')
180 {
181 fprintf(tfp, "%s", line);
182 continue;
183 }
184
185 pw = parse_user(line);
186 if (pw == (struct passwd *)NULL)
187 {
188 fprintf(stderr, "warning: bad format for entry: \"%s\"\n", line);
189 fprintf(tfp, "%s\n", line);
190 if (cfp != NULL) fprintf(cfp, "%s\n", line);
191 continue;
192 }
193
194 if (strcmp(newpw->pw_name, pw->pw_name))
195 {
196 fprintf(tfp, "%s\n", line);
197 if (cfp != NULL) fprintf(cfp, "%s\n", line);
198 continue;
199 }
200
201 fprintf(tfp, "%s:%s:%d:%d:%s:%d:%d:%s:%s:%s\n",
202 newpw->pw_name, newpw->pw_passwd, newpw->pw_uid, newpw->pw_gid,
203 newpw->pw_class, newpw->pw_change, newpw->pw_expire,
204 newpw->pw_gecos, newpw->pw_dir, newpw->pw_shell);
205 if (cfp != NULL)
206 {
207 fprintf(cfp, "%s:",newpw->pw_name);
208 if ((newpw->pw_passwd == NULL) || (newpw->pw_passwd[0] == '\0'))
209 fprintf(cfp, ":");
210 else
211 fprintf(cfp, "*:");
212 fprintf(cfp, "%d:%d:%s:%s:%s\n",
213 newpw->pw_uid, newpw->pw_gid, newpw->pw_gecos,
214 newpw->pw_dir, newpw->pw_shell);
215 }
216 }
217
218 if (cfp != NULL) fclose(cfp);
219 fclose(fp);
220 if (unlink(pwname) < 0)
221 {
222 fprintf(stderr, "can't update \"%s\": ", pwname);
223 perror("");
224 }
225
226 rewind(tfp);
227
228 fp = fopen(pwname, "w");
229 if (fp == NULL)
230 {
231 fprintf(stderr, "ERROR: lost file \"%s\"\n", pwname);
232 fprintf(stderr, "new passwd file is \"%s\"\n", fname);
233 perror("open");
234 exit(1);
235 }
236
237 while (NULL != (line = getline(tfp)))
238 {
239 fprintf(fp, "%s", line);
240 if (line[0] != '#') fprintf(fp, "\n");
241 }
242 fclose(fp);
243 fclose(tfp);
244 unlink(fname);
245}
246
247int
248file_passwd(char *uname, char *locn)
249{
250 char *ne, *oc, *nc;
251 FILE *fp;
252 char *fname;
253 struct passwd *pw;
254 struct passwd newpw;
255 int uid;
256
257 fname = _PASSWD_FILE;
258 if (locn != NULL) fname = locn;
259
260 fp = fopen(fname, "a+");
261 if (fp == NULL)
262 {
263 fprintf(stderr, "can't write to file \"%s\": ", fname);
264 perror("");
265 exit(1);
266 }
267
268
269 pw = find_user(uname, fp);
270 if (pw == (struct passwd *)NULL)
271 {
272 fprintf(stderr, "user %s not found in file %s\n", uname, fname);
273 exit(1);
274 }
275
276 uid = getuid();
277 if ((uid != 0) && (uid != pw->pw_uid))
278 {
279 fprintf(stderr, "Permission denied\n");
280 exit(1);
281 }
282
283 /*
284 * Get the new password
285 */
286 getpasswd(uname, (uid == 0), 5, 0, 0, pw->pw_passwd, &ne, &oc, &nc);
287
288 newpw.pw_name = copyString(pw->pw_name);
289 newpw.pw_passwd = copyString(ne);
290 newpw.pw_uid = pw->pw_uid;
291 newpw.pw_gid = pw->pw_gid;
292 newpw.pw_class = copyString(pw->pw_class);
293 newpw.pw_change = pw->pw_change;
294 newpw.pw_expire = pw->pw_expire;
295 newpw.pw_gecos = copyString(pw->pw_gecos);
296 newpw.pw_dir = copyString(pw->pw_dir);
297 newpw.pw_shell = copyString(pw->pw_shell);
298
299 /*
300 * Re-write the file
301 */
302 rewrite_file(fname, fp, &newpw);
303
304 /*
305 * Clean up memory
306 */
307 pw = parse_user(NULL);
308 free(newpw.pw_name);
309 free(newpw.pw_passwd);
310 free(newpw.pw_gecos);
311 free(newpw.pw_dir);
312 free(newpw.pw_shell);
313 free(newpw.pw_class);
314
315 fclose(fp);
316
317 return 0;
318}