Date: Sat, 10 Aug 2002 14:02:39 +0200 From: Eirik Nygaard <eirikn@bluezone.no> To: current@freebsd.org Subject: Rewrite of the perl script rmuser to C Message-ID: <20020810120239.GB1064@test.eirikn.net>
next in thread | raw e-mail | index | archive | help
--Hf61M2y+wYpnELGG Content-Type: multipart/mixed; boundary="ncSAzJYg3Aa9+CRW" Content-Disposition: inline --ncSAzJYg3Aa9+CRW Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable 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? --=20 Eirik Nygaard <eirikn@bluezone.no> PGP Key: 83C55EDE --ncSAzJYg3Aa9+CRW Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="rmuser.c" Content-Transfer-Encoding: quoted-printable /* ** -*- 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 permis= sion. ** ** 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 <eirikn@bluezone.no>, 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[] =3D "/etc/master.passwd"; char passwd_tmp[] =3D "/etc/ptmp"; char group_file[] =3D "/etc/group"; char new_group_file[] =3D "/etc/group.new"; char mail_dir[] =3D "/var/mail"; char crontab_dir[] =3D "/var/cron/tabs"; char path[] =3D "/bin:/sbin:/usr/bin:/usr/sbin"; int yes =3D 0; // Always yes? int removehomedir =3D 1; char *user =3D 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 =3D 0; char string[1024], string2[1024], *p; struct sigaction sa; /* Check for root */ if (getuid() !=3D 0) { printf("You must be root to run this program.\n"); _exit(-2); } sa.sa_handler =3D sig_handler1; sigemptyset(&sa.sa_mask); sa.sa_flags =3D SA_RESTART; sigaction(SIGINT, &sa, NULL); sa.sa_handler =3D sig_handler2; sigaction(SIGQUIT, &sa, NULL); sa.sa_handler =3D sig_handler3; sigaction(SIGHUP, &sa, NULL); sa.sa_handler =3D sig_handler4; sigaction(SIGTERM, &sa, NULL); =09 =09 /* Set the path we need */ setenv("PATH", path, 1); =09 /* Set umode */ umask(022); =09 /* Get command line arguments */ while ((ch =3D getopt(argc, argv, "yu:")) !=3D -1) { switch (ch) { case 'y': yes =3D 1; break; case 'u': user =3D optarg; break; case '?': default: usage(argv[0]); } } =09 if ((fp =3D open(passwd_file, O_RDONLY)) =3D=3D 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) =3D=3D -1) { printf("Unable to lock passwd file(%s).\n", passwd_file); _exit(-4); } =09 if (user =3D=3D NULL) { getuser(); } =09 while (recvnl(string, fp) !=3D -1) { strcpy(string2, string); if ((p =3D strtok(string, ":")) !=3D NULL) { if (strcasecmp(p, user) =3D=3D 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 =3D=3D 0) { printf("Is this the entry you wish to remove?(y/n) "); fgets(answer, sizeof(answer), stdin); if (strncmp(answer, "y", 1) !=3D 0 && strncmp(answer, "Y", 1) !=3D 0) { printf("User %s not removed.\n", user); _exit(1); } } if (flock(fp, LOCK_UN) =3D=3D -1) {=09 printf("Unable to unlock passwd file(%s).\n", passwd_file); _exit(-5); } close(fp); =09 if ((password =3D getpwnam(user)) =3D=3D NULL) { printf("Unable to get user info for user %s.\n", user); _exit(-11); } if (yes =3D=3D 0) { printf("Remove homedir(%s)?(y/n) ", password->pw_dir); fgets(answer, sizeof(answer), stdin); if (strncmp(answer, "y", 1) =3D=3D 0 || strncmp(answer, "Y", 1) =3D=3D 0)= =20 removehomedir =3D 1; else=20 removehomedir =3D 0; } else { removehomedir =3D 1; } strncpy(homedir, password->pw_dir, sizeof(homedir)); next2: lstat(homedir, &sb); if (removehomedir =3D=3D 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 =3D 0; } if (S_ISLNK(sb.st_mode)) { numbuf =3D readlink(password->pw_dir, homedir, sizeof(homedir)); printf("%s\n", homedir); homedir[numbuf] =3D '\0'; goto next2; } if (sb.st_uid !=3D password->pw_uid) { if (removehomedir =3D=3D 1) printf("Home %s is not owned by %s, so it will not be removed.\n", home= dir, user); removehomedir =3D 0; } } killuser(password->pw_uid, password->pw_gid); update_passwd(); update_group(); if (removehomedir =3D=3D 1) { printf("Removeing home %s.\n", homedir); remove_files_from_dir(password->pw_uid, homedir); if (rmdir(homedir) =3D=3D -1) printf("Warning: Unable to remove home %s - continuing.\n", homedir); } =09 sprintf(line, "%s/%s", crontab_dir, user); if ((fp2 =3D fopen(line, "r")) !=3D NULL) { fclose(fp2); if (unlink(line) =3D=3D -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"); =09 return 0; } void usage(char *progname) { printf("Usage: %s [-y] [-u username]\n", progname);=09 _exit(-1); } void getuser() { printf("Enter login name for user to remove: "); fgets(user2, sizeof(user2), stdin); user2[strlen(user2) - 1] =3D '\0'; user =3D user2; } void remove_files_from_dir(int uid, char *path) { int Tmp; struct dirent *DirEntryPtr; DIR *DirPtr; struct stat Stat; char Path[1024]; =09 DirPtr =3D opendir(path); while (1) { DirEntryPtr =3D readdir(DirPtr);=09 if (DirEntryPtr =3D=3D 0) break; if (strcmp(DirEntryPtr->d_name,".") !=3D 0 && strcmp(DirEntryPtr->d_name,= "..") !=3D 0) { Path[0] =3D 0; strcat(Path,homedir); strcat(Path,"/"); strcat(Path,DirEntryPtr->d_name); Tmp =3D stat(Path,&Stat);=20 if (S_ISDIR(Stat.st_mode)) { remove_files_from_dir(uid, Path); if (Stat.st_uid =3D=3D uid) if (rmdir(Path) =3D=3D -1) printf("Warning: Unable to remove dir %s - continuing.\n", Path); } if (Stat.st_uid =3D=3D uid) { //printf("Removeing file %s\n", Path); if (unlink(Path) =3D=3D -1)=20 printf("Warning: unlink on %s failed - continuing.\n", Path); } =09 } =09 } return; } void update_passwd() { int fp_pw, fp2_pw; char string[1024], string2[1024]; int skipped =3D 0; =09 if ((fp_pw =3D open(passwd_file, O_RDONLY|O_EXLOCK)) =3D=3D -1) { printf("Warning: Unable to open %s, so can not remove the user - continui= ng.\n", passwd_file); return; } if ((fp2_pw =3D open(passwd_tmp, O_WRONLY|O_EXLOCK|O_CREAT, 0600)) =3D=3D = -1) { printf("Warning: Unable to open %s, so can not remove the user - continui= ng.\n", passwd_tmp); return; } sprintf(string2, "%s:", user); next3: while (recvnl(string, fp) !=3D -1) { if (strncmp(string, "#", 1) =3D=3D 0) goto next3; if (strncasecmp(string, string2, strlen(user) + 1) !=3D 0) { write(fp2_pw, string, strlen(string)); write(fp2_pw, "\n", 1); }=20 else { if (skipped =3D=3D 1) { write(fp2_pw, string, strlen(string)); write(fp2_pw, "\n", 1); } //printf("Droped entry for %s\n", string); skipped =3D 1; } } if (skipped =3D=3D 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); } =09 close(fp_pw); close(fp2_pw); /* Rebuild db */ sprintf(line, "/usr/sbin/pwd_mkdb -p %s", passwd_tmp); system(line); =09 return; } void update_group() { char string[1024], string2[1024], string3[1024]; int fp_g, fp2_g, users; char *p, *p2; int a =3D 0; char group[1024], gid[1024], pass[1024], users2[1024], users3[1024]; if ((fp_g =3D open(group_file, O_RDONLY|O_EXLOCK)) =3D=3D -1) { printf("Warning: Unable to open %s, so can not remove the user's grou= p - continuing.\n", passwd_file); return; } =20 if ((fp2_g =3D open(new_group_file, O_WRONLY|O_EXLOCK|O_CREAT, 0644)) = =3D=3D -1) { printf("Warning: Unable to open %s, so can not remove the user's grou= p - continuing.\n", passwd_tmp); return; } =20 sprintf(string2, "%s:", user); next4: while (recvnl(string, fp) !=3D -1) { if (strncmp(string, "#", 1) =3D=3D 0) goto next4; if (strncasecmp(string, string2, strlen(user) + 1) !=3D 0) { // Check if user is in the group string3[0] =3D '\0'; strcpy(string3, string); for (p =3D strtok(string3, ":\n"); p !=3D NULL; p =3D strtok(NULL, ":\n"= )) { if (a =3D=3D 0) strcpy(group, p); if (a =3D=3D 1) strcpy(pass, p); if (a =3D=3D 2) strcpy(gid, p); if (a =3D=3D 3) strcpy(users2, p); a++; } a =3D 0; users3[0] =3D '\0'; for (p =3D strtok(users2, ",\n"); p !=3D NULL; p =3D strtok(NULL, ",\n")= ) { if (strcasecmp(user, p) !=3D 0) { if (a =3D=3D 0) { strcat(users3, p); a =3D 1; } else {=20 strcat(users3, ","); strcat(users3, p); } } } sprintf(string3, "%s:%s:%s:%s\n", group, pass, gid, users3); /*printf("<%s>\n", string3);*/ =09 write(fp2_g, string3, strlen(string3)); a =3D 0; } else { // Check if there is other users added to the group p =3D string; while (*p !=3D ':') *p++; // Skip groupname *p++; while (*p !=3D ':') *p++; // Skip password sectiona *p++; while (*p !=3D ':') *p++; // Skip gid section *p++; strcpy(string3, p); for (p2 =3D strtok(string3, ","); p2 !=3D NULL; p2 =3D strtok(NULL, ","= )) { users =3D 1; } if (users =3D=3D 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); =09 rename(new_group_file, group_file); return; } int recvnl( char *buf, int fd) { int bytes =3D 0; char buf2[2]; char buf3[1024]; buf3[0] =3D '\0'; while ( read(fd, buf2, 1) !=3D 0) { buf2[1] =3D '\0'; if (strncmp(buf2, "\n", 1) =3D=3D 0) { strcpy(buf, buf3); return bytes; } else if (strncmp(buf2, "\r", 1) !=3D 0) { strcat(buf3, buf2); bytes++; } } return -1; } /* Kill users processes */ void killuser(int uid, int gid) { int pid;=09 =09 if (( pid =3D fork()) =3D=3D 0) { setgid(gid); setuid(uid); if (getuid() !=3D uid || getgid() !=3D gid) { printf("Warning: Unable to set gid or uid, so I can't kill the users pro= cesses - continuing.\n"); _exit(-1); } kill(0, 15); sleep(1); kill(0, 9); _exit(0); } else { while (waitpid(-1,NULL,WNOHANG) !=3D pid) ; } } void del_mail() { char string[1024]; FILE *file; =09 =09 sprintf(string, "%s/%s", mail_dir, user); if ((file =3D fopen(string, "r")) !=3D NULL) { printf("Removing %s mail file.\n", user); fclose(file); if (unlink(string) =3D=3D -1) printf("\tWarning: Unable to remove mail file %s.\n", string); } =09 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() !=3D 0) return; printf("\nCaught signal SIGTERM -- cleaning up.\n"); unlink(passwd_tmp); unlink(new_group_file); _exit(5); } =09 --ncSAzJYg3Aa9+CRW-- --Hf61M2y+wYpnELGG Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.7 (FreeBSD) iD8DBQE9VQDe1JB0Z4PFXt4RAl0xAJ9dTA1VDdkMCCEhUNRsX98AmMuS6ACfQ0Id KF1u61Beyps7bYPDc887eak= =Nt30 -----END PGP SIGNATURE----- --Hf61M2y+wYpnELGG-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020810120239.GB1064>