summaryrefslogtreecommitdiffstats
path: root/system_cmds/passwd.tproj/file_passwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'system_cmds/passwd.tproj/file_passwd.c')
-rw-r--r--system_cmds/passwd.tproj/file_passwd.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/system_cmds/passwd.tproj/file_passwd.c b/system_cmds/passwd.tproj/file_passwd.c
new file mode 100644
index 0000000..62d27f3
--- /dev/null
+++ b/system_cmds/passwd.tproj/file_passwd.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include "passwd.h"
+
+#define _PASSWD_FILE "/etc/master.passwd"
+#define _COMPAT_FILE "/etc/passwd"
+#define _PASSWD_FIELDS 10
+#define BUFSIZE 8192
+
+void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
+
+static struct passwd *
+parse_user(char *line, size_t len)
+{
+ static struct passwd pw;
+ int i,j;
+ char *tokens[_PASSWD_FIELDS];
+ char *token = NULL;
+ bool comment = true;
+
+ free(pw.pw_name);
+ free(pw.pw_passwd);
+ free(pw.pw_class);
+ free(pw.pw_gecos);
+ free(pw.pw_dir);
+ free(pw.pw_shell);
+ memset(&pw, 0, sizeof(pw));
+
+ if (line == NULL) return NULL;
+
+ memset(&tokens, 0, sizeof(char *) * _PASSWD_FIELDS);
+
+ for (i = 0, j = 0; i < len && j < _PASSWD_FIELDS; ++i) {
+ int c = line[i];
+ if (!isspace(c) && c != '#') {
+ comment = false;
+ }
+ if (!comment && token == NULL) {
+ // start a new token
+ token = &line[i];
+ } else if (token && (c == ':' || c == '\n')) {
+ // end the current token
+ // special case for empty token
+ while (token[0] == ':' && token < &line[i]) {
+ tokens[j++] = strdup("");
+ ++token;
+ }
+ tokens[j++] = strndup(token, &line[i] - token);
+ token = NULL;
+ }
+ }
+
+ if (comment || j != _PASSWD_FIELDS) return NULL;
+
+ j = 0;
+ pw.pw_name = tokens[j++];
+ pw.pw_passwd = tokens[j++];
+ pw.pw_uid = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_gid = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_class = tokens[j++];
+ pw.pw_change = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_expire = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_gecos = tokens[j++];
+ pw.pw_dir = tokens[j++];
+ pw.pw_shell = tokens[j++];
+
+ return &pw;
+}
+
+static struct passwd *
+find_user(FILE *fp, char *uname)
+{
+ size_t len;
+ char *line;
+
+ rewind(fp);
+
+ while ((line = fgetln(fp, &len)) != NULL) {
+ struct passwd *pw = parse_user(line, len);
+ if (pw && strcmp(uname, pw->pw_name) == 0) {
+ return pw;
+ }
+ }
+ return NULL;
+}
+
+static void
+rewrite_file(char *path, FILE *fp, struct passwd *newpw)
+{
+ int fd;
+ char *line;
+ size_t len;
+ FILE *tfp = NULL;
+ char *tempname = NULL; // temporary master.passwd file
+
+ asprintf(&tempname, "%s.XXXXXX", path);
+
+ fd = mkstemp(tempname);
+ if (fd == -1) {
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+ tfp = fdopen(fd, "w+");
+ if (tfp == NULL || fchmod(fd, S_IRUSR | S_IWUSR) != 0) {
+ int save = errno;
+ unlink(tempname);
+ errno = save;
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+
+ while ((line = fgetln(fp, &len)) != NULL) {
+ struct passwd *pw = parse_user(line, len);
+
+ // if this is not the entry we're looking for or if parsing
+ // failed (likely a comment) then print the entry as is.
+ if (pw == NULL || strcmp(newpw->pw_name, pw->pw_name) != 0) {
+ fwrite(line, sizeof(char), len, tfp);
+ } else {
+ fprintf(tfp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ newpw->pw_name,
+ newpw->pw_passwd,
+ newpw->pw_uid,
+ newpw->pw_gid,
+ newpw->pw_class,
+ newpw->pw_change,
+ newpw->pw_expire,
+ newpw->pw_gecos,
+ newpw->pw_dir,
+ newpw->pw_shell);
+ }
+ }
+
+ // Move the temporary file into place.
+ if (fclose(tfp) != 0 || rename(tempname, path) != 0) {
+ int save = errno;
+ unlink(tempname);
+ errno = save;
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+
+ free(tempname);
+}
+
+int
+file_passwd(char *uname, char *locn)
+{
+ char *ne, *oc, *nc;
+ int fd;
+ FILE *fp;
+ uid_t uid;
+ char *fname;
+ struct passwd *pw;
+ struct passwd newpw;
+
+ fname = _PASSWD_FILE;
+ if (locn != NULL) fname = locn;
+
+ fd = open(fname, O_RDONLY | O_EXLOCK);
+ if (fd == -1) {
+ err(EXIT_FAILURE, "%s", fname);
+ }
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL) {
+ err(EXIT_FAILURE, "%s", fname);
+ }
+
+ pw = find_user(fp, uname);
+ if (pw == NULL) {
+ errx(EXIT_FAILURE, "user %s not found in %s", uname, fname);
+ }
+
+ uid = getuid();
+ if (uid != 0 && uid != pw->pw_uid) {
+ errno = EACCES;
+ err(EXIT_FAILURE, "%s", uname);
+ }
+
+ // Get the password
+ getpasswd(uname, (uid == 0), 5, 0, 0, pw->pw_passwd, &ne, &oc, &nc);
+
+ newpw.pw_name = strdup(pw->pw_name);
+ newpw.pw_passwd = strdup(ne);
+ newpw.pw_uid = pw->pw_uid;
+ newpw.pw_gid = pw->pw_gid;
+ newpw.pw_class = strdup(pw->pw_class);
+ newpw.pw_change = pw->pw_change;
+ newpw.pw_expire = pw->pw_expire;
+ newpw.pw_gecos = strdup(pw->pw_gecos);
+ newpw.pw_dir = strdup(pw->pw_dir);
+ newpw.pw_shell = strdup(pw->pw_shell);
+
+ // Rewrite the file
+ rewind(fp);
+ rewrite_file(fname, fp, &newpw);
+
+ fclose(fp);
+
+ return 0;
+}