]> git.saurik.com Git - apple/system_cmds.git/blame - passwd.tproj/file_passwd.c
system_cmds-541.tar.gz
[apple/system_cmds.git] / passwd.tproj / file_passwd.c
CommitLineData
1815bff5 1/*
8459d725 2 * Copyright (c) 1999-2010 Apple Inc. All rights reserved.
1815bff5
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
8459d725
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
1815bff5
A
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
8459d725
A
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
1815bff5
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
8459d725
A
23#include <ctype.h>
24#include <err.h>
25#include <errno.h>
26#include <fcntl.h>
27#include <pwd.h>
ef8ad44b 28#include <signal.h>
8459d725
A
29#include <stdbool.h>
30#include <stdlib.h>
1815bff5 31#include <stdio.h>
20e66415 32#include <string.h>
1376a029 33#include <sysexits.h>
8459d725 34#include <unistd.h>
1376a029 35#include <sys/time.h>
1376a029 36#include <sys/stat.h>
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
8459d725 43void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
1815bff5 44
8459d725
A
45static struct passwd *
46parse_user(char *line, size_t len)
1815bff5 47{
8459d725
A
48 static struct passwd pw;
49 int i,j;
50 char *tokens[_PASSWD_FIELDS];
51 char *token = NULL;
52 bool comment = true;
53
54 free(pw.pw_name);
55 free(pw.pw_passwd);
56 free(pw.pw_class);
57 free(pw.pw_gecos);
58 free(pw.pw_dir);
59 free(pw.pw_shell);
60 memset(&pw, 0, sizeof(pw));
61
62 if (line == NULL) return NULL;
63
64 memset(&tokens, 0, sizeof(char *) * _PASSWD_FIELDS);
65
66 for (i = 0, j = 0; i < len && j < _PASSWD_FIELDS; ++i) {
67 int c = line[i];
68 if (!isspace(c) && c != '#') {
69 comment = false;
70 }
71 if (!comment && token == NULL) {
72 // start a new token
73 token = &line[i];
74 } else if (token && (c == ':' || c == '\n')) {
75 // end the current token
76 // special case for empty token
77 while (token[0] == ':' && token < &line[i]) {
78 tokens[j++] = strdup("");
79 ++token;
80 }
81 tokens[j++] = strndup(token, &line[i] - token);
82 token = NULL;
83 }
1815bff5
A
84 }
85
8459d725
A
86 if (comment || j != _PASSWD_FIELDS) return NULL;
87
88 j = 0;
89 pw.pw_name = tokens[j++];
90 pw.pw_passwd = tokens[j++];
91 pw.pw_uid = atoi(tokens[j]);
92 free(tokens[j++]);
93 pw.pw_gid = atoi(tokens[j]);
94 free(tokens[j++]);
95 pw.pw_class = tokens[j++];
96 pw.pw_change = atoi(tokens[j]);
97 free(tokens[j++]);
98 pw.pw_expire = atoi(tokens[j]);
99 free(tokens[j++]);
100 pw.pw_gecos = tokens[j++];
101 pw.pw_dir = tokens[j++];
102 pw.pw_shell = tokens[j++];
1815bff5
A
103
104 return &pw;
105}
106
8459d725
A
107static struct passwd *
108find_user(FILE *fp, char *uname)
1815bff5 109{
8459d725 110 size_t len;
1815bff5 111 char *line;
1815bff5
A
112
113 rewind(fp);
114
8459d725
A
115 while ((line = fgetln(fp, &len)) != NULL) {
116 struct passwd *pw = parse_user(line, len);
117 if (pw && strcmp(uname, pw->pw_name) == 0) {
118 return pw;
119 }
1815bff5 120 }
8459d725 121 return NULL;
1815bff5
A
122}
123
8459d725
A
124static void
125rewrite_file(char *path, FILE *fp, struct passwd *newpw)
1815bff5 126{
1376a029 127 int fd;
8459d725
A
128 char *line;
129 size_t len;
130 FILE *tfp = NULL;
131 char *tempname = NULL; // temporary master.passwd file
132
133 asprintf(&tempname, "%s.XXXXXX", path);
1815bff5 134
8459d725
A
135 fd = mkstemp(tempname);
136 if (fd == -1) {
137 err(EXIT_FAILURE, "%s", tempname);
1376a029
A
138 }
139 tfp = fdopen(fd, "w+");
8459d725
A
140 if (tfp == NULL || fchmod(fd, S_IRUSR | S_IWUSR) != 0) {
141 int save = errno;
142 unlink(tempname);
143 errno = save;
144 err(EXIT_FAILURE, "%s", tempname);
145 }
146
147 while ((line = fgetln(fp, &len)) != NULL) {
148 struct passwd *pw = parse_user(line, len);
149
150 // if this is not the entry we're looking for or if parsing
151 // failed (likely a comment) then print the entry as is.
152 if (pw == NULL || strcmp(newpw->pw_name, pw->pw_name) != 0) {
153 fwrite(line, sizeof(char), len, tfp);
154 } else {
155 fprintf(tfp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
156 newpw->pw_name,
157 newpw->pw_passwd,
158 newpw->pw_uid,
159 newpw->pw_gid,
160 newpw->pw_class,
161 newpw->pw_change,
162 newpw->pw_expire,
163 newpw->pw_gecos,
164 newpw->pw_dir,
165 newpw->pw_shell);
1815bff5
A
166 }
167 }
168
8459d725
A
169 // Move the temporary file into place.
170 if (fclose(tfp) != 0 || rename(tempname, path) != 0) {
171 int save = errno;
172 unlink(tempname);
173 errno = save;
174 err(EXIT_FAILURE, "%s", tempname);
1815bff5 175 }
1815bff5 176
8459d725 177 free(tempname);
1815bff5
A
178}
179
180int
8459d725 181file_passwd(char *uname, char *locn)
1815bff5
A
182{
183 char *ne, *oc, *nc;
8459d725 184 int fd;
1815bff5 185 FILE *fp;
8459d725 186 uid_t uid;
1815bff5
A
187 char *fname;
188 struct passwd *pw;
189 struct passwd newpw;
1376a029 190
1815bff5
A
191 fname = _PASSWD_FILE;
192 if (locn != NULL) fname = locn;
1376a029 193
8459d725
A
194 fd = open(fname, O_RDONLY | O_EXLOCK);
195 if (fd == -1) {
196 err(EXIT_FAILURE, "%s", fname);
1376a029 197 }
8459d725
A
198
199 fp = fdopen(fd, "r");
200 if (fp == NULL) {
201 err(EXIT_FAILURE, "%s", fname);
1376a029 202 }
8459d725
A
203
204 pw = find_user(fp, uname);
205 if (pw == NULL) {
206 errx(EXIT_FAILURE, "user %s not found in %s", uname, fname);
1815bff5
A
207 }
208
209 uid = getuid();
8459d725
A
210 if (uid != 0 && uid != pw->pw_uid) {
211 errno = EACCES;
212 err(EXIT_FAILURE, "%s", uname);
1815bff5
A
213 }
214
8459d725 215 // Get the password
1815bff5
A
216 getpasswd(uname, (uid == 0), 5, 0, 0, pw->pw_passwd, &ne, &oc, &nc);
217
8459d725
A
218 newpw.pw_name = strdup(pw->pw_name);
219 newpw.pw_passwd = strdup(ne);
1815bff5
A
220 newpw.pw_uid = pw->pw_uid;
221 newpw.pw_gid = pw->pw_gid;
8459d725 222 newpw.pw_class = strdup(pw->pw_class);
1815bff5
A
223 newpw.pw_change = pw->pw_change;
224 newpw.pw_expire = pw->pw_expire;
8459d725
A
225 newpw.pw_gecos = strdup(pw->pw_gecos);
226 newpw.pw_dir = strdup(pw->pw_dir);
227 newpw.pw_shell = strdup(pw->pw_shell);
1815bff5 228
8459d725
A
229 // Rewrite the file
230 rewind(fp);
231 rewrite_file(fname, fp, &newpw);
1815bff5
A
232
233 fclose(fp);
234
235 return 0;
236}