* @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"
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)
}
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))
{
fprintf(cfp, "# Do not edit this file. Changes will be lost.\n");
fprintf(cfp, "#\n");
}
-
+
rewind(fp);
while (NULL != (line = getline(fp)))
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);
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);
}
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)
{
/*
* Re-write the file
*/
- rewrite_file(fname, fp, &newpw);
+ rewrite_file(fname, fp, &newpw, locn);
/*
* Clean up memory
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;
+}
+