]> git.saurik.com Git - apple/system_cmds.git/blobdiff - passwd.tproj/file_passwd.c
system_cmds-433.8.tar.gz
[apple/system_cmds.git] / passwd.tproj / file_passwd.c
index 0cff1d445c5e306ee96140d5008efe08f170b376..65a862f27ee8d2e533aed1eba28e937c3491ae9f 100644 (file)
  * @APPLE_LICENSE_HEADER_END@
  */
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <pwd.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <sysexits.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
 #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"
@@ -37,7 +45,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)
@@ -129,23 +137,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))
        {
@@ -170,7 +195,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)))
@@ -196,8 +221,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);
@@ -216,23 +241,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);
@@ -244,27 +271,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)
        {
@@ -298,7 +352,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
@@ -315,3 +369,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;
+}
+