]> git.saurik.com Git - apple/system_cmds.git/blame - passwd.tproj/file_passwd.c
system_cmds-336.1.2.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 *
2fc1e207
A
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
1815bff5
A
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2fc1e207
A
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
1815bff5
A
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24#include <stdio.h>
20e66415 25#include <string.h>
1815bff5
A
26#include <stdlib.h>
27#include <unistd.h>
28#include <pwd.h>
29#include <errno.h>
d1ccfde8
A
30#include <fcntl.h>
31#include <sysexits.h>
32#include <sys/stat.h>
1815bff5
A
33#include "stringops.h"
34
d1ccfde8
A
35#define TEMP_FILE_TEMPLATE "/var/run/.pwtmpXXXXXX"
36#define LOCK_FILE "/var/run/.passwd.lock"
1815bff5
A
37
38#define _PASSWD_FILE "/etc/master.passwd"
39#define _COMPAT_FILE "/etc/passwd"
40#define _PASSWD_FIELDS 10
41#define BUFSIZE 8192
42
43extern void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
44
2fc1e207 45//static int do_compat = 1; (unused)
1815bff5
A
46
47char *
48getline(FILE *fp)
49{
50 static char s[BUFSIZE];
51 int len;
52
53 s[0] = '\0';
54
55 fgets(s, BUFSIZE, fp);
56 if (s == NULL || s[0] == '\0') return NULL;
57
58 if (s[0] == '#') return s;
59
60 len = strlen(s) - 1;
61 s[len] = '\0';
62
63 return s;
64}
65
66struct passwd *
67parse_user(char *line)
68{
69 static struct passwd pw = {0};
70 char **tokens;
71 int i, len;
72
73 if (pw.pw_name != NULL) free(pw.pw_name);
74 pw.pw_name = NULL;
75 if (pw.pw_passwd != NULL) free(pw.pw_passwd);
76 pw.pw_passwd = NULL;
77 if (pw.pw_gecos != NULL) free(pw.pw_gecos);
78 pw.pw_gecos = NULL;
79 if (pw.pw_dir != NULL) free(pw.pw_dir);
80 pw.pw_dir = NULL;
81 if (pw.pw_shell != NULL) free(pw.pw_shell);
82 pw.pw_shell = NULL;
83
84 if (pw.pw_class != NULL) free(pw.pw_class);
85 pw.pw_class = NULL;
86
87 if (line == NULL) return (struct passwd *)NULL;
88 tokens = explode(line, ':');
89 len = listLength(tokens);
90
91 if (len != _PASSWD_FIELDS)
92 {
93 freeList(tokens);
94 return (struct passwd *)NULL;
95 }
96
97 i = 0;
98 pw.pw_name = tokens[i++];
99 pw.pw_passwd = tokens[i++];
100 pw.pw_uid = atoi(tokens[i]);
101 free(tokens[i++]);
102 pw.pw_gid = atoi(tokens[i]);
103 free(tokens[i++]);
104 pw.pw_class = tokens[i++];
105 pw.pw_change = atoi(tokens[i]);
106 free(tokens[i++]);
107 pw.pw_expire = atoi(tokens[i]);
108 free(tokens[i++]);
109 pw.pw_gecos = tokens[i++];
110 pw.pw_dir = tokens[i++];
111 pw.pw_shell = tokens[i++];
112
113 return &pw;
114}
115
116struct passwd *
117find_user(char *uname, FILE *fp)
118{
119 char *line;
120 struct passwd *pw;
121
122 rewind(fp);
123
124 while (NULL != (line = getline(fp)))
125 {
126 if (line[0] == '#') continue;
127 pw = parse_user(line);
128 if (pw == (struct passwd *)NULL) continue;
129 if (!strcmp(uname, pw->pw_name)) return pw;
130 }
131
132 pw = parse_user(NULL);
133 return (struct passwd *)NULL;
134}
135
136void
d1ccfde8 137rewrite_file(char *pwname, FILE *fp, struct passwd *newpw, char *locn)
1815bff5
A
138{
139 char *line;
140 struct passwd *pw;
141 FILE *tfp, *cfp;
d1ccfde8 142 int fd;
1815bff5
A
143 char fname[256];
144
d1ccfde8
A
145 sprintf(fname, "%s.%.5d", TEMP_FILE_TEMPLATE, getpid());
146 fd = mkstemps(fname, 6);
147 if (fd == -1)
148 {
149 fprintf(stderr, "can't create temporary file \"%s\": ", fname);
150 perror("");
151 exit(1);
152 }
153 if (fchmod(fd, (S_IRUSR | S_IWUSR)) != 0)
154 {
155 close(fd);
156 unlink(fname);
157 fprintf(stderr, "can't set permissions for temporary file \"%s\": ", fname);
158 perror("");
159 exit(1);
160 }
161 tfp = fdopen(fd, "w+");
1815bff5
A
162 if (tfp == NULL)
163 {
d1ccfde8
A
164 close(fd);
165 unlink(fname);
1815bff5
A
166 fprintf(stderr, "can't write temporary file \"%s\": ", fname);
167 perror("");
168 exit(1);
169 }
d1ccfde8 170
1815bff5
A
171 cfp = NULL;
172 if (!strcmp(pwname, _PASSWD_FILE))
173 {
174 cfp = fopen(_COMPAT_FILE, "w");
175 if (cfp == NULL)
176 {
177 fprintf(stderr, "warning: can't write compatability file \"%s\": ",
178 _COMPAT_FILE);
179 perror("");
180 }
181 }
182
183 if (cfp != NULL)
184 {
185 fprintf(cfp, "#\n");
186 fprintf(cfp, "# 4.3BSD-compatable User Database\n");
187 fprintf(cfp, "#\n");
188 fprintf(cfp, "# Note that this file is not consulted for login.\n");
189 fprintf(cfp, "# It only exisits for compatability with 4.3BSD utilities.\n");
190 fprintf(cfp, "#\n");
191 fprintf(cfp, "# This file is automatically re-written by various system utilities.\n");
192 fprintf(cfp, "# Do not edit this file. Changes will be lost.\n");
193 fprintf(cfp, "#\n");
194 }
d1ccfde8 195
1815bff5
A
196 rewind(fp);
197
198 while (NULL != (line = getline(fp)))
199 {
200 if (line[0] == '#')
201 {
202 fprintf(tfp, "%s", line);
203 continue;
204 }
205
206 pw = parse_user(line);
207 if (pw == (struct passwd *)NULL)
208 {
209 fprintf(stderr, "warning: bad format for entry: \"%s\"\n", line);
210 fprintf(tfp, "%s\n", line);
211 if (cfp != NULL) fprintf(cfp, "%s\n", line);
212 continue;
213 }
214
215 if (strcmp(newpw->pw_name, pw->pw_name))
216 {
217 fprintf(tfp, "%s\n", line);
218 if (cfp != NULL) fprintf(cfp, "%s\n", line);
219 continue;
220 }
2fc1e207
A
221
222 fprintf(tfp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
1815bff5
A
223 newpw->pw_name, newpw->pw_passwd, newpw->pw_uid, newpw->pw_gid,
224 newpw->pw_class, newpw->pw_change, newpw->pw_expire,
225 newpw->pw_gecos, newpw->pw_dir, newpw->pw_shell);
226 if (cfp != NULL)
227 {
228 fprintf(cfp, "%s:",newpw->pw_name);
229 if ((newpw->pw_passwd == NULL) || (newpw->pw_passwd[0] == '\0'))
230 fprintf(cfp, ":");
231 else
232 fprintf(cfp, "*:");
233 fprintf(cfp, "%d:%d:%s:%s:%s\n",
234 newpw->pw_uid, newpw->pw_gid, newpw->pw_gecos,
235 newpw->pw_dir, newpw->pw_shell);
236 }
237 }
238
239 if (cfp != NULL) fclose(cfp);
240 fclose(fp);
d1ccfde8 241
1815bff5
A
242 rewind(tfp);
243
d1ccfde8
A
244 if (locn != NULL) {
245 if (setuid(getuid()) != 0) {
246 fprintf(stderr, "Unable to set privileges.");
247 perror("setuid");
248 exit(1);
249 }
250 }
1815bff5
A
251 fp = fopen(pwname, "w");
252 if (fp == NULL)
253 {
d1ccfde8 254 fprintf(stderr, "ERROR: can't update \"%s\"\n", pwname);
1815bff5
A
255 fprintf(stderr, "new passwd file is \"%s\"\n", fname);
256 perror("open");
257 exit(1);
258 }
d1ccfde8 259
1815bff5
A
260 while (NULL != (line = getline(tfp)))
261 {
262 fprintf(fp, "%s", line);
263 if (line[0] != '#') fprintf(fp, "\n");
264 }
265 fclose(fp);
266 fclose(tfp);
267 unlink(fname);
268}
269
270int
d1ccfde8 271_file_passwd_main(char *uname, char *locn)
1815bff5
A
272{
273 char *ne, *oc, *nc;
274 FILE *fp;
275 char *fname;
276 struct passwd *pw;
277 struct passwd newpw;
278 int uid;
279
280 fname = _PASSWD_FILE;
281 if (locn != NULL) fname = locn;
d1ccfde8
A
282
283 umask((S_IRWXG | S_IRWXO));
1815bff5
A
284 fp = fopen(fname, "a+");
285 if (fp == NULL)
286 {
287 fprintf(stderr, "can't write to file \"%s\": ", fname);
288 perror("");
289 exit(1);
290 }
d1ccfde8
A
291 if (fchmod(fileno(fp), (S_IRUSR | S_IWUSR)) != 0)
292 {
293 fclose(fp);
294 fprintf(stderr, "can't set permissions for file \"%s\": ", fname);
295 perror("");
296 exit(1);
297 }
298
1815bff5
A
299 pw = find_user(uname, fp);
300 if (pw == (struct passwd *)NULL)
301 {
302 fprintf(stderr, "user %s not found in file %s\n", uname, fname);
303 exit(1);
304 }
305
306 uid = getuid();
307 if ((uid != 0) && (uid != pw->pw_uid))
308 {
309 fprintf(stderr, "Permission denied\n");
310 exit(1);
311 }
312
313 /*
314 * Get the new password
315 */
316 getpasswd(uname, (uid == 0), 5, 0, 0, pw->pw_passwd, &ne, &oc, &nc);
317
318 newpw.pw_name = copyString(pw->pw_name);
319 newpw.pw_passwd = copyString(ne);
320 newpw.pw_uid = pw->pw_uid;
321 newpw.pw_gid = pw->pw_gid;
322 newpw.pw_class = copyString(pw->pw_class);
323 newpw.pw_change = pw->pw_change;
324 newpw.pw_expire = pw->pw_expire;
325 newpw.pw_gecos = copyString(pw->pw_gecos);
326 newpw.pw_dir = copyString(pw->pw_dir);
327 newpw.pw_shell = copyString(pw->pw_shell);
328
329 /*
330 * Re-write the file
331 */
d1ccfde8 332 rewrite_file(fname, fp, &newpw, locn);
1815bff5
A
333
334 /*
335 * Clean up memory
336 */
337 pw = parse_user(NULL);
338 free(newpw.pw_name);
339 free(newpw.pw_passwd);
340 free(newpw.pw_gecos);
341 free(newpw.pw_dir);
342 free(newpw.pw_shell);
343 free(newpw.pw_class);
344
345 fclose(fp);
346
347 return 0;
348}
d1ccfde8
A
349
350
351void sighandler(int inSignal)
352{
353 unlink(LOCK_FILE);
354 exit(1);
355}
356
357
358int
359file_passwd(char *uname, char *locn)
360{
361 pid_t pid;
362 int retVal = 0;
363 int waitResult = 0;
364 int retries = 0;
365 struct stat sb;
366 FILE *lockFile;
367 struct sigaction action = {0};
368
369 /* trap signals */
370 sigfillset( &action.sa_mask );
371 action.sa_flags = SA_RESTART;
372 action.sa_handler = sighandler;
373 sigaction(SIGHUP, &action, NULL);
374 sigaction(SIGINT, &action, NULL); // ctrl-c
375 sigaction(SIGQUIT, &action, NULL);
376 sigaction(SIGABRT, &action, NULL);
377 sigaction(SIGPIPE, &action, NULL);
378 sigaction(SIGALRM, &action, NULL);
379 sigaction(SIGTERM, &action, NULL);
380 sigaction(SIGSTOP, &action, NULL);
381 sigaction(SIGTSTP, &action, NULL);
382
383 /* Check/create lock file */
384 for (retries = 0; retries < 5; retries++)
385 {
386 retVal = lstat(LOCK_FILE, &sb);
387 if (retVal != 0)
388 break;
389 /* try in 100 milliseconds */
390 usleep(100000);
391 }
392 if (retVal == 0)
393 {
394 fprintf(stderr, "another passwd process is running.\n");
395 exit(EX_TEMPFAIL);
396 }
397
398 umask((S_IRWXG | S_IRWXO));
399 lockFile = fopen(LOCK_FILE, "w");
400 if (lockFile == NULL)
401 {
402 fprintf(stderr, "can't create lock file.\n");
403 exit(EX_CANTCREAT);
404 }
405 fprintf(lockFile, "%d\n", getpid());
406 fclose(lockFile);
407
408 pid = fork();
409 if (pid == -1)
410 {
411 fprintf(stderr, "can't fork\n");
412 exit(EX_OSERR);
413 }
414
415 /* Handle the child */
416 if (pid == 0)
417 {
418 retVal = _file_passwd_main(uname, locn);
419 exit(retVal);
420 }
421
422 /* Handle the parent */
423 waitResult = waitpid(pid, &retVal, 0);
424 retVal = (waitResult == 0) ? WEXITSTATUS(retVal) : 1;
425
426 /* delete lock file */
427 unlink(LOCK_FILE);
428
429 return retVal;
430}
431