/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights * Reserved. 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 1.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.apple.com/publicsource 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 OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License." * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include "stringops.h" #define TEMP_FILE "/tmp/.pwtmp" #define _PASSWD_FILE "/etc/master.passwd" #define _COMPAT_FILE "/etc/passwd" #define _PASSWD_FIELDS 10 #define BUFSIZE 8192 extern void getpasswd(char *, int, int, int, int, char *, char **, char**, char **); static int do_compat = 1; char * getline(FILE *fp) { static char s[BUFSIZE]; int len; s[0] = '\0'; fgets(s, BUFSIZE, fp); if (s == NULL || s[0] == '\0') return NULL; if (s[0] == '#') return s; len = strlen(s) - 1; s[len] = '\0'; return s; } struct passwd * parse_user(char *line) { static struct passwd pw = {0}; char **tokens; int i, len; if (pw.pw_name != NULL) free(pw.pw_name); pw.pw_name = NULL; if (pw.pw_passwd != NULL) free(pw.pw_passwd); pw.pw_passwd = NULL; if (pw.pw_gecos != NULL) free(pw.pw_gecos); pw.pw_gecos = NULL; if (pw.pw_dir != NULL) free(pw.pw_dir); pw.pw_dir = NULL; if (pw.pw_shell != NULL) free(pw.pw_shell); pw.pw_shell = NULL; if (pw.pw_class != NULL) free(pw.pw_class); pw.pw_class = NULL; if (line == NULL) return (struct passwd *)NULL; tokens = explode(line, ':'); len = listLength(tokens); if (len != _PASSWD_FIELDS) { freeList(tokens); return (struct passwd *)NULL; } i = 0; pw.pw_name = tokens[i++]; pw.pw_passwd = tokens[i++]; pw.pw_uid = atoi(tokens[i]); free(tokens[i++]); pw.pw_gid = atoi(tokens[i]); free(tokens[i++]); pw.pw_class = tokens[i++]; pw.pw_change = atoi(tokens[i]); free(tokens[i++]); pw.pw_expire = atoi(tokens[i]); free(tokens[i++]); pw.pw_gecos = tokens[i++]; pw.pw_dir = tokens[i++]; pw.pw_shell = tokens[i++]; return &pw; } struct passwd * find_user(char *uname, FILE *fp) { char *line; struct passwd *pw; rewind(fp); while (NULL != (line = getline(fp))) { if (line[0] == '#') continue; pw = parse_user(line); if (pw == (struct passwd *)NULL) continue; if (!strcmp(uname, pw->pw_name)) return pw; } pw = parse_user(NULL); return (struct passwd *)NULL; } void rewrite_file(char *pwname, FILE *fp, struct passwd *newpw) { char *line; struct passwd *pw; FILE *tfp, *cfp; char fname[256]; sprintf(fname, "%s.%d", TEMP_FILE, getpid()); tfp = fopen(fname, "w+"); if (tfp == NULL) { fprintf(stderr, "can't write temporary file \"%s\": ", fname); perror(""); exit(1); } cfp = NULL; if (!strcmp(pwname, _PASSWD_FILE)) { cfp = fopen(_COMPAT_FILE, "w"); if (cfp == NULL) { fprintf(stderr, "warning: can't write compatability file \"%s\": ", _COMPAT_FILE); perror(""); } } if (cfp != NULL) { fprintf(cfp, "#\n"); fprintf(cfp, "# 4.3BSD-compatable User Database\n"); fprintf(cfp, "#\n"); fprintf(cfp, "# Note that this file is not consulted for login.\n"); fprintf(cfp, "# It only exisits for compatability with 4.3BSD utilities.\n"); fprintf(cfp, "#\n"); fprintf(cfp, "# This file is automatically re-written by various system utilities.\n"); fprintf(cfp, "# Do not edit this file. Changes will be lost.\n"); fprintf(cfp, "#\n"); } rewind(fp); while (NULL != (line = getline(fp))) { if (line[0] == '#') { fprintf(tfp, "%s", line); continue; } pw = parse_user(line); if (pw == (struct passwd *)NULL) { fprintf(stderr, "warning: bad format for entry: \"%s\"\n", line); fprintf(tfp, "%s\n", line); if (cfp != NULL) fprintf(cfp, "%s\n", line); continue; } if (strcmp(newpw->pw_name, pw->pw_name)) { fprintf(tfp, "%s\n", line); if (cfp != NULL) fprintf(cfp, "%s\n", line); continue; } fprintf(tfp, "%s:%s:%d:%d:%s:%d:%d:%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); if (cfp != NULL) { fprintf(cfp, "%s:",newpw->pw_name); if ((newpw->pw_passwd == NULL) || (newpw->pw_passwd[0] == '\0')) fprintf(cfp, ":"); else fprintf(cfp, "*:"); fprintf(cfp, "%d:%d:%s:%s:%s\n", newpw->pw_uid, newpw->pw_gid, newpw->pw_gecos, newpw->pw_dir, newpw->pw_shell); } } if (cfp != NULL) fclose(cfp); fclose(fp); if (unlink(pwname) < 0) { fprintf(stderr, "can't update \"%s\": ", pwname); perror(""); } rewind(tfp); fp = fopen(pwname, "w"); if (fp == NULL) { fprintf(stderr, "ERROR: lost file \"%s\"\n", pwname); fprintf(stderr, "new passwd file is \"%s\"\n", fname); perror("open"); exit(1); } while (NULL != (line = getline(tfp))) { fprintf(fp, "%s", line); if (line[0] != '#') fprintf(fp, "\n"); } fclose(fp); fclose(tfp); unlink(fname); } int file_passwd(char *uname, char *locn) { char *ne, *oc, *nc; FILE *fp; char *fname; struct passwd *pw; struct passwd newpw; int uid; fname = _PASSWD_FILE; if (locn != NULL) fname = locn; fp = fopen(fname, "a+"); if (fp == NULL) { fprintf(stderr, "can't write to file \"%s\": ", fname); perror(""); exit(1); } pw = find_user(uname, fp); if (pw == (struct passwd *)NULL) { fprintf(stderr, "user %s not found in file %s\n", uname, fname); exit(1); } uid = getuid(); if ((uid != 0) && (uid != pw->pw_uid)) { fprintf(stderr, "Permission denied\n"); exit(1); } /* * Get the new password */ getpasswd(uname, (uid == 0), 5, 0, 0, pw->pw_passwd, &ne, &oc, &nc); newpw.pw_name = copyString(pw->pw_name); newpw.pw_passwd = copyString(ne); newpw.pw_uid = pw->pw_uid; newpw.pw_gid = pw->pw_gid; newpw.pw_class = copyString(pw->pw_class); newpw.pw_change = pw->pw_change; newpw.pw_expire = pw->pw_expire; newpw.pw_gecos = copyString(pw->pw_gecos); newpw.pw_dir = copyString(pw->pw_dir); newpw.pw_shell = copyString(pw->pw_shell); /* * Re-write the file */ rewrite_file(fname, fp, &newpw); /* * Clean up memory */ pw = parse_user(NULL); free(newpw.pw_name); free(newpw.pw_passwd); free(newpw.pw_gecos); free(newpw.pw_dir); free(newpw.pw_shell); free(newpw.pw_class); fclose(fp); return 0; }