X-Git-Url: https://git.saurik.com/apple/system_cmds.git/blobdiff_plain/d904471cf60febf9484bc16c29e58e92baf2b9cc..ef8ad44b9b5d9c6d8c0fa5b5494f449fb6717387:/passwd.tproj/file_passwd.c diff --git a/passwd.tproj/file_passwd.c b/passwd.tproj/file_passwd.c index d439d97..ffc81ca 100644 --- a/passwd.tproj/file_passwd.c +++ b/passwd.tproj/file_passwd.c @@ -21,15 +21,23 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#include #include #include #include #include #include #include +#include +#include +#include +#include +#include +#include #include "stringops.h" -#define TEMP_FILE "/tmp/.pwtmp" +#define TEMP_FILE_TEMPLATE "/var/run/.pwtmpXXXXXX" +#define LOCK_FILE "/var/run/.passwd.lock" #define _PASSWD_FILE "/etc/master.passwd" #define _COMPAT_FILE "/etc/passwd" @@ -38,7 +46,7 @@ extern void getpasswd(char *, int, int, int, int, char *, char **, char**, char **); -static int do_compat = 1; +//static int do_compat = 1; (unused) char * getline(FILE *fp) @@ -130,23 +138,40 @@ find_user(char *uname, FILE *fp) } void -rewrite_file(char *pwname, FILE *fp, struct passwd *newpw) +rewrite_file(char *pwname, FILE *fp, struct passwd *newpw, char *locn) { char *line; struct passwd *pw; FILE *tfp, *cfp; + int fd; char fname[256]; - sprintf(fname, "%s.%d", TEMP_FILE, getpid()); - - tfp = fopen(fname, "w+"); + sprintf(fname, "%s.%.5d", TEMP_FILE_TEMPLATE, getpid()); + fd = mkstemps(fname, 6); + if (fd == -1) + { + fprintf(stderr, "can't create temporary file \"%s\": ", fname); + perror(""); + exit(1); + } + if (fchmod(fd, (S_IRUSR | S_IWUSR)) != 0) + { + close(fd); + unlink(fname); + fprintf(stderr, "can't set permissions for temporary file \"%s\": ", fname); + perror(""); + exit(1); + } + tfp = fdopen(fd, "w+"); if (tfp == NULL) { + close(fd); + unlink(fname); fprintf(stderr, "can't write temporary file \"%s\": ", fname); perror(""); exit(1); } - + cfp = NULL; if (!strcmp(pwname, _PASSWD_FILE)) { @@ -171,7 +196,7 @@ rewrite_file(char *pwname, FILE *fp, struct passwd *newpw) fprintf(cfp, "# Do not edit this file. Changes will be lost.\n"); fprintf(cfp, "#\n"); } - + rewind(fp); while (NULL != (line = getline(fp))) @@ -197,8 +222,8 @@ rewrite_file(char *pwname, FILE *fp, struct passwd *newpw) if (cfp != NULL) fprintf(cfp, "%s\n", line); continue; } - - fprintf(tfp, "%s:%s:%d:%d:%s:%d:%d:%s:%s:%s\n", + + 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); @@ -217,23 +242,25 @@ rewrite_file(char *pwname, FILE *fp, struct passwd *newpw) if (cfp != NULL) fclose(cfp); fclose(fp); - if (unlink(pwname) < 0) - { - fprintf(stderr, "can't update \"%s\": ", pwname); - perror(""); - } - + rewind(tfp); + if (locn != NULL) { + if (seteuid(getuid()) != 0) { + fprintf(stderr, "Unable to set privileges."); + perror("seteuid"); + exit(1); + } + } fp = fopen(pwname, "w"); if (fp == NULL) { - fprintf(stderr, "ERROR: lost file \"%s\"\n", pwname); + fprintf(stderr, "ERROR: can't update \"%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); @@ -245,27 +272,54 @@ rewrite_file(char *pwname, FILE *fp, struct passwd *newpw) } int -file_passwd(char *uname, char *locn) +_file_passwd_main(char *uname, char *locn) { char *ne, *oc, *nc; FILE *fp; char *fname; struct passwd *pw; struct passwd newpw; + struct stat sb; int uid; - + uid_t euid; + fname = _PASSWD_FILE; if (locn != NULL) fname = locn; - + + umask((S_IRWXG | S_IRWXO)); + + if ( lstat(fname, &sb) != 0 ) + { + fprintf(stderr, "The file does not exist.\n"); + exit(1); + } + + euid = geteuid(); + if (locn != NULL) { + if (seteuid(getuid()) != 0) { + fprintf(stderr, "Permission denied.\n"); + exit(1); + } + } fp = fopen(fname, "a+"); + if (locn != NULL) { + seteuid(euid); + } + if (fp == NULL) { fprintf(stderr, "can't write to file \"%s\": ", fname); perror(""); exit(1); } - - + if (fchmod(fileno(fp), (S_IRUSR | S_IWUSR)) != 0) + { + fclose(fp); + fprintf(stderr, "can't set permissions for file \"%s\": ", fname); + perror(""); + exit(1); + } + pw = find_user(uname, fp); if (pw == (struct passwd *)NULL) { @@ -299,7 +353,7 @@ file_passwd(char *uname, char *locn) /* * Re-write the file */ - rewrite_file(fname, fp, &newpw); + rewrite_file(fname, fp, &newpw, locn); /* * Clean up memory @@ -316,3 +370,96 @@ file_passwd(char *uname, char *locn) return 0; } + + +void sighandler(int inSignal) +{ + unlink(LOCK_FILE); + exit(1); +} + + +int +file_passwd(char *uname, char *locn) +{ + pid_t pid; + int retVal = 0; + int waitResult = 0; + int retries = 0; + struct stat sb; + FILE *lockFile; + struct sigaction action = {{0}}; + struct rlimit rlim; + + /* unlimit the resource limits */ + rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; + (void)setrlimit(RLIMIT_CPU, &rlim); + (void)setrlimit(RLIMIT_FSIZE, &rlim); + (void)setrlimit(RLIMIT_STACK, &rlim); + (void)setrlimit(RLIMIT_DATA, &rlim); + (void)setrlimit(RLIMIT_RSS, &rlim); + (void)setrlimit(RLIMIT_NOFILE, &rlim); + + /* trap signals */ + sigfillset( &action.sa_mask ); + action.sa_flags = SA_RESTART; + action.sa_handler = sighandler; + sigaction(SIGHUP, &action, NULL); + sigaction(SIGINT, &action, NULL); // ctrl-c + sigaction(SIGQUIT, &action, NULL); + sigaction(SIGABRT, &action, NULL); + sigaction(SIGPIPE, &action, NULL); + sigaction(SIGALRM, &action, NULL); + sigaction(SIGTERM, &action, NULL); + sigaction(SIGSTOP, &action, NULL); + sigaction(SIGTSTP, &action, NULL); + + /* Check/create lock file */ + for (retries = 0; retries < 5; retries++) + { + retVal = lstat(LOCK_FILE, &sb); + if (retVal != 0) + break; + /* try in 100 milliseconds */ + usleep(100000); + } + if (retVal == 0) + { + fprintf(stderr, "another passwd process is running.\n"); + exit(EX_TEMPFAIL); + } + + umask((S_IRWXG | S_IRWXO)); + lockFile = fopen(LOCK_FILE, "w"); + if (lockFile == NULL) + { + fprintf(stderr, "can't create lock file.\n"); + exit(EX_CANTCREAT); + } + fprintf(lockFile, "%d\n", getpid()); + fclose(lockFile); + + pid = fork(); + if (pid == -1) + { + fprintf(stderr, "can't fork\n"); + exit(EX_OSERR); + } + + /* Handle the child */ + if (pid == 0) + { + retVal = _file_passwd_main(uname, locn); + exit(retVal); + } + + /* Handle the parent */ + waitResult = waitpid(pid, &retVal, 0); + retVal = (waitResult == 0) ? WEXITSTATUS(retVal) : 1; + + /* delete lock file */ + unlink(LOCK_FILE); + + return retVal; +} +