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);
}

Attachment: msg41808/pgp00000.pgp
Description: PGP signature

Reply via email to