]> git.saurik.com Git - apple/system_cmds.git/blame - passwd.tproj/file_passwd.c
system_cmds-880.100.5.tar.gz
[apple/system_cmds.git] / passwd.tproj / file_passwd.c
CommitLineData
1815bff5 1/*
cf37c299 2 * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
1815bff5
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
cf37c299 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.
cf37c299 12 *
1815bff5
A
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.
cf37c299 20 *
1815bff5
A
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>
aaff5f01 37#include "passwd.h"
1815bff5
A
38
39#define _PASSWD_FILE "/etc/master.passwd"
40#define _COMPAT_FILE "/etc/passwd"
41#define _PASSWD_FIELDS 10
42#define BUFSIZE 8192
43
8459d725 44void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
1815bff5 45
8459d725
A
46static struct passwd *
47parse_user(char *line, size_t len)
1815bff5 48{
8459d725
A
49 static struct passwd pw;
50 int i,j;
51 char *tokens[_PASSWD_FIELDS];
52 char *token = NULL;
53 bool comment = true;
54
55 free(pw.pw_name);
56 free(pw.pw_passwd);
57 free(pw.pw_class);
58 free(pw.pw_gecos);
59 free(pw.pw_dir);
60 free(pw.pw_shell);
61 memset(&pw, 0, sizeof(pw));
62
63 if (line == NULL) return NULL;
64
65 memset(&tokens, 0, sizeof(char *) * _PASSWD_FIELDS);
66
67 for (i = 0, j = 0; i < len && j < _PASSWD_FIELDS; ++i) {
68 int c = line[i];
69 if (!isspace(c) && c != '#') {
70 comment = false;
71 }
72 if (!comment && token == NULL) {
73 // start a new token
74 token = &line[i];
75 } else if (token && (c == ':' || c == '\n')) {
76 // end the current token
77 // special case for empty token
78 while (token[0] == ':' && token < &line[i]) {
79 tokens[j++] = strdup("");
80 ++token;
81 }
82 tokens[j++] = strndup(token, &line[i] - token);
83 token = NULL;
84 }
1815bff5
A
85 }
86
8459d725
A
87 if (comment || j != _PASSWD_FIELDS) return NULL;
88
89 j = 0;
90 pw.pw_name = tokens[j++];
91 pw.pw_passwd = tokens[j++];
92 pw.pw_uid = atoi(tokens[j]);
93 free(tokens[j++]);
94 pw.pw_gid = atoi(tokens[j]);
95 free(tokens[j++]);
96 pw.pw_class = tokens[j++];
97 pw.pw_change = atoi(tokens[j]);
98 free(tokens[j++]);
99 pw.pw_expire = atoi(tokens[j]);
100 free(tokens[j++]);
101 pw.pw_gecos = tokens[j++];
102 pw.pw_dir = tokens[j++];
103 pw.pw_shell = tokens[j++];
1815bff5
A
104
105 return &pw;
106}
107
8459d725
A
108static struct passwd *
109find_user(FILE *fp, char *uname)
1815bff5 110{
8459d725 111 size_t len;
1815bff5 112 char *line;
1815bff5
A
113
114 rewind(fp);
115
8459d725
A
116 while ((line = fgetln(fp, &len)) != NULL) {
117 struct passwd *pw = parse_user(line, len);
118 if (pw && strcmp(uname, pw->pw_name) == 0) {
119 return pw;
120 }
1815bff5 121 }
8459d725 122 return NULL;
1815bff5
A
123}
124
8459d725
A
125static void
126rewrite_file(char *path, FILE *fp, struct passwd *newpw)
1815bff5 127{
1376a029 128 int fd;
8459d725
A
129 char *line;
130 size_t len;
131 FILE *tfp = NULL;
132 char *tempname = NULL; // temporary master.passwd file
133
134 asprintf(&tempname, "%s.XXXXXX", path);
cf37c299 135
8459d725
A
136 fd = mkstemp(tempname);
137 if (fd == -1) {
138 err(EXIT_FAILURE, "%s", tempname);
1376a029
A
139 }
140 tfp = fdopen(fd, "w+");
8459d725
A
141 if (tfp == NULL || fchmod(fd, S_IRUSR | S_IWUSR) != 0) {
142 int save = errno;
143 unlink(tempname);
144 errno = save;
145 err(EXIT_FAILURE, "%s", tempname);
146 }
cf37c299 147
8459d725
A
148 while ((line = fgetln(fp, &len)) != NULL) {
149 struct passwd *pw = parse_user(line, len);
150
151 // if this is not the entry we're looking for or if parsing
152 // failed (likely a comment) then print the entry as is.
153 if (pw == NULL || strcmp(newpw->pw_name, pw->pw_name) != 0) {
154 fwrite(line, sizeof(char), len, tfp);
155 } else {
156 fprintf(tfp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
157 newpw->pw_name,
158 newpw->pw_passwd,
159 newpw->pw_uid,
160 newpw->pw_gid,
161 newpw->pw_class,
162 newpw->pw_change,
163 newpw->pw_expire,
164 newpw->pw_gecos,
165 newpw->pw_dir,
166 newpw->pw_shell);
1815bff5
A
167 }
168 }
169
8459d725
A
170 // Move the temporary file into place.
171 if (fclose(tfp) != 0 || rename(tempname, path) != 0) {
172 int save = errno;
173 unlink(tempname);
174 errno = save;
175 err(EXIT_FAILURE, "%s", tempname);
1815bff5 176 }
1815bff5 177
8459d725 178 free(tempname);
1815bff5
A
179}
180
181int
8459d725 182file_passwd(char *uname, char *locn)
1815bff5
A
183{
184 char *ne, *oc, *nc;
8459d725 185 int fd;
1815bff5 186 FILE *fp;
8459d725 187 uid_t uid;
1815bff5
A
188 char *fname;
189 struct passwd *pw;
190 struct passwd newpw;
cf37c299 191
1815bff5
A
192 fname = _PASSWD_FILE;
193 if (locn != NULL) fname = locn;
cf37c299 194
8459d725
A
195 fd = open(fname, O_RDONLY | O_EXLOCK);
196 if (fd == -1) {
197 err(EXIT_FAILURE, "%s", fname);
1376a029 198 }
8459d725
A
199
200 fp = fdopen(fd, "r");
201 if (fp == NULL) {
202 err(EXIT_FAILURE, "%s", fname);
1376a029 203 }
8459d725
A
204
205 pw = find_user(fp, uname);
206 if (pw == NULL) {
207 errx(EXIT_FAILURE, "user %s not found in %s", uname, fname);
1815bff5
A
208 }
209
210 uid = getuid();
8459d725
A
211 if (uid != 0 && uid != pw->pw_uid) {
212 errno = EACCES;
213 err(EXIT_FAILURE, "%s", uname);
1815bff5
A
214 }
215
8459d725 216 // Get the password
1815bff5
A
217 getpasswd(uname, (uid == 0), 5, 0, 0, pw->pw_passwd, &ne, &oc, &nc);
218
8459d725
A
219 newpw.pw_name = strdup(pw->pw_name);
220 newpw.pw_passwd = strdup(ne);
1815bff5
A
221 newpw.pw_uid = pw->pw_uid;
222 newpw.pw_gid = pw->pw_gid;
8459d725 223 newpw.pw_class = strdup(pw->pw_class);
1815bff5
A
224 newpw.pw_change = pw->pw_change;
225 newpw.pw_expire = pw->pw_expire;
8459d725
A
226 newpw.pw_gecos = strdup(pw->pw_gecos);
227 newpw.pw_dir = strdup(pw->pw_dir);
228 newpw.pw_shell = strdup(pw->pw_shell);
1815bff5 229
8459d725
A
230 // Rewrite the file
231 rewind(fp);
232 rewrite_file(fname, fp, &newpw);
1815bff5
A
233
234 fclose(fp);
235
236 return 0;
237}