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