I have just rewritten the rmuser perl script to C, it would be great if you could take 
a look at it and check if everything is ok.

How do I get this commited?

-- 

Eirik Nygaard <[EMAIL PROTECTED]>
PGP Key: 83C55EDE

/*
** -*- perl -*-
** Copyright 1995, 1996, 1997 Guy Helmer, Ames, Iowa 50014.
** 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 GUY HELMER ``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
**
** $FreeBSD$
*/

/*
** TODO:
** Add an at remove function
*/


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <dirent.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#include <sys/wait.h>


char passwd_file[] = "/etc/master.passwd";
char passwd_tmp[] = "/etc/ptmp";
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 = 0; // Always yes?
int removehomedir = 1;
char *user = NULL; // User to delete
char user2[400];
char answer[400];
int fp;
FILE *fp2;
char line[1024];
char homedir[1024];

struct passwd *password;
struct stat sb;

void usage(char *progname);
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 sig_handler1();
void sig_handler2();
void sig_handler3();
void sig_handler4();

int main(int argc, char **argv) {
        int ch, numbuf = 0;
        char string[1024], string2[1024], *p;
        struct sigaction sa;

        /* Check for root */
        if (getuid() != 0) {
                printf("You must be root to run this program.\n");
                _exit(-2);
        }
        sa.sa_handler = sig_handler1;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = SA_RESTART;
        sigaction(SIGINT, &sa, NULL);
        sa.sa_handler = sig_handler2;
        sigaction(SIGQUIT, &sa, NULL);
        sa.sa_handler = sig_handler3;
        sigaction(SIGHUP, &sa, NULL);
        sa.sa_handler = sig_handler4;
        sigaction(SIGTERM, &sa, NULL);
        
        
        /* 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(argv[0]);
                }
        }
        
        if ((fp = open(passwd_file, O_RDONLY)) == NULL) {
                printf("Unable to open passwd file(%s).\n", passwd_file);
                _exit(-3);
        }
        fcntl(fp, F_SETFD, 1);
        if (flock(fp, LOCK_EX|LOCK_NB) == -1) {
                printf("Unable to lock passwd file(%s).\n", passwd_file);
                _exit(-4);
        }

        
        if (user == NULL) {
                getuser();
        }
        
        while (recvnl(string, fp) != -1) {
                strcpy(string2, string);
                if ((p = strtok(string, ":")) != NULL) {
                        if (strcasecmp(p, user) == 0) {
                                printf("Matching password entry: \n\n");
                                printf("%s\n", string2);
                                goto next1;
                        }
                }
        }
        printf("No user by that name found.\n");
        _exit(-6);
        next1:
        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 (flock(fp, LOCK_UN) == -1) { 
                printf("Unable to unlock passwd file(%s).\n", passwd_file);
                _exit(-5);
        }
        close(fp);
        
        if ((password = getpwnam(user)) == NULL) {
                printf("Unable to get user info for user %s.\n", user);
                _exit(-11);
        }
        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));
        next2:
        lstat(homedir, &sb);
        if (removehomedir == 1) {
                if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode)) {
                        printf("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 next2;
                }
                if (sb.st_uid != password->pw_uid) {
                        if (removehomedir == 1)
                                printf("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)
                        printf("Warning: Unable to remove home %s - continuing.\n", 
homedir);
        }
        
        sprintf(line, "%s/%s", crontab_dir, user);
        if ((fp2 = fopen(line, "r")) != NULL) {
                fclose(fp2);
                if (unlink(line) == -1)
                        printf("Warning: Unable to remove crontab file %s - 
continuing.\n", line);
                printf("Removeing users' crontab: ");
                sprintf(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(char *progname) {
        printf("Usage: %s [-y] [-u username]\n", progname);     
        _exit(-1);
}
void getuser() {
        printf("Enter login name for user to remove: ");
        fgets(user2, sizeof(user2), stdin);
        user2[strlen(user2) - 1] = '\0';
        user = user2;
}

void remove_files_from_dir(int uid, char *path) {
        int Tmp;
        struct dirent *DirEntryPtr;
        DIR *DirPtr;
        struct stat Stat;
        char Path[1024];
        
        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;
                        strcat(Path,homedir);
                        strcat(Path,"/");
                        strcat(Path,DirEntryPtr->d_name);
                        Tmp = stat(Path,&Stat); 
                        if (S_ISDIR(Stat.st_mode)) {
                                remove_files_from_dir(uid, Path);
                                if (Stat.st_uid == uid)
                                        if (rmdir(Path) == -1)
                                                printf("Warning: Unable to remove dir 
%s - continuing.\n", Path);
                        }
                        if (Stat.st_uid == uid) {
                                //printf("Removeing file %s\n", Path);
                                if (unlink(Path) == -1) 
                                        printf("Warning: unlink on %s failed - 
continuing.\n", Path);
                        }
                
                }
                
        }
        return;
}

void update_passwd() {
        int fp_pw, fp2_pw;
        char string[1024], string2[1024];
        int skipped = 0;
        
        if ((fp_pw = open(passwd_file, O_RDONLY|O_EXLOCK)) == -1) {
                printf("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;
        }
        sprintf(string2, "%s:", user);
        next3:
        while (recvnl(string, fp) != -1) {
                if (strncmp(string, "#", 1) == 0) goto next3;
                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);
                sprintf(line, "/bin/rm -f %s", passwd_tmp);
                system(line);
                _exit(-10);
        }
        
        close(fp_pw); close(fp2_pw);
        /* Rebuild db */
        sprintf(line, "/usr/sbin/pwd_mkdb -p %s", passwd_tmp);
        system(line);
        
        return;
}

void update_group() {
        char string[1024], string2[1024], string3[1024];
        int fp_g, fp2_g, users;
        char *p, *p2;
        int a = 0;
        char group[1024], gid[1024], pass[1024], users2[1024], users3[1024];

        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;
   }  
        sprintf(string2, "%s:", user);
        next4:
        while (recvnl(string, fp) != -1) {
                if (strncmp(string, "#", 1) == 0) goto next4;
                if (strncasecmp(string, string2, strlen(user) + 1) != 0) {
                        // Check if user is in the group
                        string3[0] = '\0';
                        strcpy(string3, string);
                        for (p = strtok(string3, ":\n"); p != NULL; p = strtok(NULL, 
":\n")) {
                                if (a == 0)
                                        strcpy(group, p);
                                if (a == 1)
                                        strcpy(pass, p);
                                if (a == 2)
                                        strcpy(gid, p);
                                if (a == 3)
                                        strcpy(users2, p);
                                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) {
                                                strcat(users3, p);
                                                a = 1;
                                        } else { 
                                                strcat(users3, ",");
                                                strcat(users3, p);
                                        }
                                }
                        }
                        sprintf(string3, "%s:%s:%s:%s\n", group, pass, gid, users3);
                        /*printf("<%s>\n", string3);*/
                        
              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 sectiona
                                *p++;
                                while (*p != ':') *p++; // Skip gid section
                                *p++;
                                strcpy(string3, p);
                                for (p2 = strtok(string3, ","); p2 != NULL; p2 = 
strtok(NULL, ",")) {
                                        users = 1;
                                }
                                if (users == 1) {
                                        printf("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);

        return;
}

int recvnl( char *buf, int fd) {
   int bytes = 0;
        char buf2[2];
        char buf3[1024];

   buf3[0] = '\0';
        while ( read(fd, buf2, 1) != 0) {
                buf2[1] = '\0';
                if (strncmp(buf2, "\n", 1) == 0) {
                        strcpy(buf, buf3);
                   return bytes;
           }
           else if (strncmp(buf2, "\r", 1) != 0) {
                   strcat(buf3, buf2);
              bytes++;
           }
   }

   return -1;
}

/* Kill users processes */
void killuser(int uid, int gid) {
        int pid;        
        
        if (( pid = fork()) == 0) {
                setgid(gid);
                setuid(uid);
                if (getuid() != uid || getgid() != gid) {
                        printf("Warning: Unable to set gid or uid, so I can't kill the 
users processes - continuing.\n");
                        _exit(-1);
                }
                kill(0, 15);
                sleep(1);
                kill(0, 9);
                _exit(0);
        } else {
                while (waitpid(-1,NULL,WNOHANG) != pid)
                        ;
        }
}

void del_mail() {
        char string[1024];
        FILE *file;
        
        
        sprintf(string, "%s/%s", mail_dir, user);
        if ((file = fopen(string, "r")) != NULL) {
                printf("Removing %s mail file.\n", user);
                fclose(file);
                if (unlink(string) == -1)
                        printf("\tWarning: Unable to remove mail file %s.\n", string);
        }
        
        return;
}

void sig_handler1() {
        printf("\nCaught signal SIGINT -- cleaning up.\n");
        unlink(passwd_tmp);
        unlink(new_group_file);
        _exit(5);
}

void sig_handler2() {
   printf("\nCaught signal SIGQUIT -- cleaning up.\n");
   unlink(passwd_tmp);
   unlink(new_group_file);
        _exit(5);
}

void sig_handler3() {
   printf("\nCaught signal SIGHUP -- cleaning up.\n");
   unlink(passwd_tmp);
   unlink(new_group_file);
        _exit(5);
}

void sig_handler4() {
        if (getuid() != 0)
                return;
   printf("\nCaught signal SIGTERM -- cleaning up.\n");
   unlink(passwd_tmp);
   unlink(new_group_file);
        _exit(5);
}
                        

Attachment: msg41746/pgp00000.pgp
Description: PGP signature

Reply via email to