Hello, I sent a mail about this program with a source a couple of days ago, not really pretty code, cleaned it up and gotten some help from #bsdcode@EFnet with some fixes. So I send the source again so you could take another look at it and tell me if I am missing something.
-- Eirik Nygaard <[EMAIL PROTECTED]> Http://kverka.org/~eirik/ PGP Key: 83C55EDE
/* * Copyright 2002 Eirik Nygaard. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer as * the first lines of this file unmodified. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY EIRIK NYGAARD ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL GUY HELMER BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * rmuser - C programme to remove users * * Eirik Nygaard <[EMAIL PROTECTED]>, 08/08/02 * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); #include <sys/types.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/uio.h> #include <sys/wait.h> #include <sys/resource.h> #include <err.h> #include <fcntl.h> #include <dirent.h> #include <pwd.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sysexits.h> #include <unistd.h> #include <limits.h> #include <errno.h> char passwd_file[] = "/etc/master.passwd"; char passwd_tmp[PATH_MAX] = "/etc/ptmp.XXXXX"; char *passwd_tmp2; char group_file[] = "/etc/group"; char new_group_file[] = "/etc/group.new"; char mail_dir[] = "/var/mail"; char crontab_dir[] = "/var/cron/tabs"; char path[] = "/bin:/sbin:/usr/bin:/usr/sbin"; int yes; /* Always yes? */ int removehomedir = 1; char *user = NULL; /* User to delete */ char user2[BUFSIZ]; char answer[BUFSIZ]; int fp; FILE *fp2; char line[PATH_MAX + 50]; char homedir[PATH_MAX]; struct passwd *password; struct stat sb; void usage(); void getuser(); void remove_files_from_dir(int uid, char *path); int recvnl( char *buf, int fd); void update_passwd(); void update_group(); void killuser(int uid, int gid); void del_mail(); void sighandle(int sig); int main(int argc, char **argv) { int ch, numbuf = 0; /* Check for root */ if (getuid() != 0) { errx(EX_NOPERM, "You must be root to run this program."); } signal(SIGINT, sighandle); signal(SIGTERM, sighandle); signal(SIGHUP, sighandle); signal(SIGQUIT, sighandle); /* Set the path we need */ setenv("PATH", path, 1); /* Set umode */ umask(022); /* Get command line arguments */ while ((ch = getopt(argc, argv, "yu:")) != -1) { switch (ch) { case 'y': yes = 1; break; case 'u': user = optarg; break; case '?': default: usage(); } } if (user == NULL) { getuser(); } if ((password = getpwnam(user)) == NULL) { errx(EX_NOUSER, "No user found by that name: %s.\n", user); } printf("\nMatching password entry: \n"); printf("\t%s:%s:%d:%d:%s:%s\n", password->pw_name, password->pw_passwd, password->pw_uid, password->pw_gid, password->pw_dir, password->pw_shell); if (yes == 0) { printf("Is this the entry you wish to remove?(y/n) "); fgets(answer, sizeof(answer), stdin); if (strncmp(answer, "y", 1) != 0 && strncmp(answer, "Y", 1) != 0) { printf("User %s not removed.\n", user); exit(1); } } if ((password = getpwnam(user)) == NULL) { errx(EX_NOUSER, "No user found by that name: %s.\n", user); } if (yes == 0) { printf("Remove homedir(%s)?(y/n) ", password->pw_dir); fgets(answer, sizeof(answer), stdin); if (strncmp(answer, "y", 1) == 0 || strncmp(answer, "Y", 1) == 0) removehomedir = 1; else removehomedir = 0; } else { removehomedir = 1; } strncpy(homedir, password->pw_dir, sizeof(homedir)); next: lstat(homedir, &sb); if (removehomedir == 1) { if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode)) { warnx("Home %s is not a directory, so it won't be removed\n", homedir); removehomedir = 0; } if (S_ISLNK(sb.st_mode)) { numbuf = readlink(password->pw_dir, homedir, sizeof(homedir)); printf("%s\n", homedir); homedir[numbuf] = '\0'; goto next; } if (sb.st_uid != password->pw_uid) { if (removehomedir == 1) warnx("Home %s is not owned by %s, so it will not be removed.\n", homedir, user); removehomedir = 0; } } killuser(password->pw_uid, password->pw_gid); update_passwd(); update_group(); if (removehomedir == 1) { printf("Removeing home %s.\n", homedir); remove_files_from_dir(password->pw_uid, homedir); if (rmdir(homedir) == -1) warn("Warning: Unable to remove home %s - continuing.\n", homedir); } snprintf(line, sizeof(line), "%s/%s", crontab_dir, user); if ((fp2 = fopen(line, "r")) != NULL) { fclose(fp2); if (unlink(line) == -1) warn("Warning: Unable to remove crontab file %s - continuing.\n", line); printf("Removeing users' crontab: "); snprintf(line, sizeof(line), "/usr/bin/crontab -u %s -r", user); system(line); printf("done.\n"); } del_mail(); printf("Removing files belonging to %s from /tmp.\n", user); remove_files_from_dir(password->pw_uid, "/tmp"); printf("Removing files belonging to %s from /var/tmp.\n", user); remove_files_from_dir(password->pw_uid, "/var/tmp"); return 0; } void usage() { printf("Usage: %s [-y] [-u username]\n", getprogname()); exit(1); } void getuser() { printf("Enter login name for user to remove: "); fgets(user2, sizeof(user2), stdin); user2[strlen(user2) - 1] = '\0'; user = user2; } /* Remove all files and folders belonging to uid in path */ void remove_files_from_dir(int uid, char *path) { int Tmp; struct dirent *DirEntryPtr; DIR *DirPtr; struct stat Stat; char Path[PATH_MAX]; DirPtr = opendir(path); while (1) { DirEntryPtr = readdir(DirPtr); if (DirEntryPtr == 0) break; if (strcmp(DirEntryPtr->d_name,".") != 0 && strcmp(DirEntryPtr->d_name,"..") != 0) { Path[0] = 0; strlcat(Path,homedir, sizeof(Path)); strlcat(Path,"/", sizeof(Path)); strlcat(Path,DirEntryPtr->d_name, sizeof(Path)); Tmp = lstat(Path,&Stat); if (S_ISDIR(Stat.st_mode)) { remove_files_from_dir(uid, Path); if (Stat.st_uid == uid) if (rmdir(Path) == -1) warn("Warning: Unable to remove dir %s - continuing.\n", Path); } if (Stat.st_uid == uid) { /* printf("Removeing file %s\n", Path); */ if (unlink(Path) == -1) warn("Warning: unlink on %s failed - continuing.\n", Path); } } } closedir(DirPtr); } /* Remove the user from the passwd file */ void update_passwd() { int fp_pw, fp2_pw; char string[BUFSIZ], string2[BUFSIZ]; int skipped = 0; if ((fp_pw = open(passwd_file, O_RDONLY|O_EXLOCK)) == -1) { warn("Warning: Unable to open %s, so can not remove the user - continuing.\n", passwd_file); return; } if ((fp2_pw = open(passwd_tmp, O_WRONLY|O_EXLOCK|O_CREAT, 0600)) == -1) { printf("Warning: Unable to open %s, so can not remove the user - continuing.\n", passwd_tmp); return; } snprintf(string2, sizeof(string2), "%s:", user); while (recvnl(string, fp) != -1) { if (strncmp(string, "#", 1) == 0) { write(fp2_pw, string, strlen(string)); continue; } if (strncasecmp(string, string2, strlen(user) + 1) != 0) { write(fp2_pw, string, strlen(string)); write(fp2_pw, "\n", 1); } else { if (skipped == 1) { write(fp2_pw, string, strlen(string)); write(fp2_pw, "\n", 1); } /* printf("Droped entry for %s\n", string); */ skipped = 1; } } if (skipped == 0) { printf("Whoops! Didn't find %s's entry second time around!\n", user); close(fp_pw); close(fp2_pw); exit(1); } close(fp_pw); close(fp2_pw); /* Rebuild db */ snprintf(line, sizeof(line), "/usr/sbin/pwd_mkdb -p %s", passwd_tmp); system(line); } /* Remove user from the group file and the users group */ void update_group() { char string[BUFSIZ], string2[BUFSIZ], string3[BUFSIZ]; int fp_g, fp2_g, users; char *p, *p2; int a = 0; char group[BUFSIZ], gid[BUFSIZ], pass[BUFSIZ], users2[BUFSIZ], users3[BUFSIZ]; if ((fp_g = open(group_file, O_RDONLY|O_EXLOCK)) == -1) { printf("Warning: Unable to open %s, so can not remove the user's group - continuing.\n", passwd_file); return; } if ((fp2_g = open(new_group_file, O_WRONLY|O_EXLOCK|O_CREAT, 0644)) == -1) { printf("Warning: Unable to open %s, so can not remove the user's group - continuing.\n", passwd_tmp); return; } snprintf(string2, sizeof(string2), "%s:", user); while (recvnl(string, fp_g) != -1) { if (strncmp(string, "#", 1) == 0) { write(fp2_g, string, strlen(string)); continue; } if (strncasecmp(string, string2, strlen(user) + 1) != 0) { /* Check if user is in the group */ string3[0] = '\0'; strlcpy(string3, string, sizeof(string3)); for (p = strtok(string3, ":\n"); p != NULL; p = strtok(NULL, ":\n")) { switch(a) { case 0: strlcpy(group, p, sizeof(group)); break; case 1: strlcpy(pass, p, sizeof(pass)); break; case 2: strlcpy(gid, p, sizeof(gid)); break; case 3: strlcpy(users2, p, sizeof(users2)); break; } a++; } a = 0; users3[0] = '\0'; for (p = strtok(users2, ",\n"); p != NULL; p = strtok(NULL, ",\n")) { if (strcasecmp(user, p) != 0) { if (a == 0) { strlcat(users3, p, sizeof(users3)); a = 1; } else { strlcat(users3, ",", sizeof(users3)); strlcat(users3, p, sizeof(users3)); } } } snprintf(string3, sizeof(string3), "%s:%s:%s:%s\n", group, pass, gid, users3); write(fp2_g, string3, strlen(string3)); a = 0; } else { /* Check if there is other users added to the group */ p = string; while (*p != ':') *p++; /* Skip groupname */ *p++; while (*p != ':') *p++; /* Skip password section */ *p++; while (*p != ':') *p++; /* Skip gid section */ *p++; strlcpy(string3, p, sizeof(string3)); for (p2 = strtok(string3, ","); p2 != NULL; p2 = strtok(NULL, ",")) { users = 1; } if (users == 1) { warnx("Warning: Other users in group %s, not removing - continuing.\n", user); write(fp2_g, string, strlen(string)); } else { /* printf("Droped entry %s\n", string); */ } } } close(fp_g); close(fp2_g); rename(new_group_file, group_file); } /* Recieve a string from fd untill a \n */ int recvnl(char *buf, int fd) { int bytes = 0; char buf2[2]; char buf3[BUFSIZ]; buf3[0] = '\0'; while ( read(fd, buf2, 1) != 0) { buf2[1] = '\0'; if (strncmp(buf2, "\n", 1) == 0) { strncpy(buf, buf3, BUFSIZ); return bytes; } else { strlcat(buf3, buf2, sizeof(buf3)); bytes++; } } return -1; } /* Kill users processes */ void killuser(int uid, int gid) { int pid; if (( pid = fork()) == 0) { if (setgid(gid) == -1) { warn("Warning: Unable to set gid - continuing.\n"); return; } if (setuid(uid) == -1) { warn("Warning: Unable to set uid - continuing.\n"); return; } kill(0, SIGTERM); sleep(1); kill(0, SIGKILL); exit(1); } if (pid == -1) { warn("Error creating child processes - continuing.\n"); return; } else { while (waitpid(-1,NULL,0) != pid) ; /* Do nothing */ } } void del_mail() { char string[BUFSIZ]; snprintf(string, sizeof(string), "%s/%s", mail_dir, user); if (unlink(string) < 0 && errno != ENOENT) warn("can't remove mailbox: %s", string); } /* Signal handeling */ void sighandle(int sig) { char unknown[] = "UNKNOWN", sint[] = "SIGINT", squit[] = "SIGQUIT", shup[] = "SIGHUP", sterm[] = "SGITERM"; struct iovec vec[3]; char msg1[] = "\nCaught signal ", msg2[] = " -- cleaning up\n"; vec[0].iov_base = msg1; vec[0].iov_len = sizeof(msg1) - 1; vec[2].iov_base = msg2; vec[2].iov_len = sizeof(msg2) - 1; switch (sig) { case SIGINT: vec[1].iov_base = sint; vec[1].iov_len = sizeof(sint) - 1; break; case SIGQUIT: vec[1].iov_base = squit; vec[1].iov_len = sizeof(squit) - 1; break; case SIGTERM: vec[1].iov_base = sterm; vec[1].iov_len = sizeof(sterm) - 1; break; case SIGHUP: vec[1].iov_base = shup; vec[1].iov_len = sizeof(shup) - 1; break; default: vec[1].iov_base = unknown; vec[1].iov_len = sizeof(unknown) - 1; break; } writev(STDOUT_FILENO, vec, sizeof(vec) / sizeof(*vec)); unlink(passwd_tmp); unlink(new_group_file); close(fp); exit(1); }
msg41808/pgp00000.pgp
Description: PGP signature