Date: Sat, 9 Nov 2002 16:27:12 +0100 From: Eirik Nygaard <eirikn@bluezone.no> To: current@freebsd.org Subject: rmuser Message-ID: <20021109152711.GA746@eirikn.net>
next in thread | raw e-mail | index | archive | help
--U+BazGySraz5kW0T Content-Type: multipart/mixed; boundary="/9DWx/yDrRhgMJTb" Content-Disposition: inline --/9DWx/yDrRhgMJTb Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable I have rewritten the rmuser.perl script into C. But got no experiense with = at, and I see the the perl port got a function that removes any at jobs for= the user being removed. So I wonderd if anyone could make a patch that doe= s that, any feedback on the code or bug reports would also be greate.=20 I have sent in a mail once before, fixed all the style bugs since them :) The source is attached. --=20 Eirik Nygaard <eirikn@bluezone.no> PGP Key: 83C55EDE --/9DWx/yDrRhgMJTb Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="rmuser.c" Content-Transfer-Encoding: quoted-printable /* * Copyright 2002 Eirik Nygaard.=20 * 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 <eirikn@bluezone.no>, 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[] =3D "/etc/master.passwd"; char passwd_tmp[PATH_MAX] =3D "/etc/ptmp.XXXXX"; char *passwd_tmp2; 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; /* Always yes? */ int removehomedir =3D 1; char *user =3D 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=20 main(int argc, char **argv)=20 { int ch, numbuf =3D 0; /* Check for root */ if (getuid() !=3D 0)=20 errx(EX_NOPERM, "You must be root to run this program."); =09 signal(SIGINT, sighandle); signal(SIGTERM, sighandle); signal(SIGHUP, sighandle); signal(SIGQUIT, sighandle); =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; =09 case 'u': user =3D optarg; break; =09 case '?': default: usage(); } } =09 if (user =3D=3D NULL) { getuser(); } =09 if ((password =3D getpwnam(user)) =3D=3D NULL)=20 errx(EX_NOUSER, "No user found by that name: %s.\n", user); =09 printf("\nMatching password entry: \n"); printf("\t%s:%s:%d:%d:%s:%s\n", password->pw_name, password->pw_passwd, pa= ssword->pw_uid, password->pw_gid, password->pw_dir, password->pw_shell); =09 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); } } =09 if ((password =3D getpwnam(user)) =3D=3D NULL)=20 errx(EX_NOUSER, "No user found by that name: %s.\n", user); =09 =09 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=20 removehomedir =3D 1; =09 =09 strncpy(homedir, password->pw_dir, sizeof(homedir)); next: lstat(homedir, &sb); if (removehomedir =3D=3D 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 =3D 0; } =09 if (S_ISLNK(sb.st_mode)) { numbuf =3D readlink(password->pw_dir, homedir, sizeof(homedir)); printf("%s\n", homedir); homedir[numbuf] =3D '\0'; goto next; } =09 if (sb.st_uid !=3D password->pw_uid) { if (removehomedir =3D=3D 1) warnx("Home %s is not owned by %s, so it will not be removed.\n", homed= ir, user); removehomedir =3D 0; } =09 } =09 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) warn("Warning: Unable to remove home %s - continuing.\n", homedir); } =09 snprintf(line, sizeof(line), "%s/%s", crontab_dir, user); if ((fp2 =3D fopen(line, "r")) !=3D NULL) { fclose(fp2); if (unlink(line) =3D=3D -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"); } =09 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=20 usage() { printf("Usage: %s [-y] [-u username]\n", getprogname());=09 exit(1); } void=20 getuser() { printf("Enter login name for user to remove: "); fgets(user2, sizeof(user2), stdin); user2[strlen(user2) - 1] =3D '\0'; user =3D user2; } /* Remove all files and folders belonging to uid in path */ void=20 remove_files_from_dir(int uid, char *path) { int Tmp; struct dirent *DirEntryPtr; DIR *DirPtr; struct stat Stat; char Path[PATH_MAX]; =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; strlcat(Path,homedir, sizeof(Path)); strlcat(Path,"/", sizeof(Path)); strlcat(Path,DirEntryPtr->d_name, sizeof(Path)); Tmp =3D lstat(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) warn("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 warn("Warning: unlink on %s failed - continuing.\n", Path); } } =09 } closedir(DirPtr); } /* Remove the user from the passwd file */ void=20 update_passwd() { int fp_pw, fp2_pw; char string[BUFSIZ], string2[BUFSIZ]; int skipped =3D 0; =09 if ((fp_pw =3D open(passwd_file, O_RDONLY|O_EXLOCK)) =3D=3D -1) { warn("Warning: Unable to open %s, so can not remove the user - continuing= .\n", passwd_file); return; } =09 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; } =09 snprintf(string2, sizeof(string2), "%s:", user); while (recvnl(string, fp) !=3D -1) { if (strncmp(string, "#", 1) =3D=3D 0) { write(fp2_pw, string, strlen(string)); continue; } if (strncasecmp(string, string2, strlen(user) + 1) !=3D 0) { write(fp2_pw, string, strlen(string)); write(fp2_pw, "\n", 1); } else { if (skipped =3D=3D 1) { write(fp2_pw, string, strlen(string)); write(fp2_pw, "\n", 1); } =09 /* printf("Droped entry for %s\n", string); */ skipped =3D 1; } } =09 if (skipped =3D=3D 0) { printf("Whoops! Didn't find %s's entry second time around!\n", user); close(fp_pw); close(fp2_pw); exit(1); } =09 close(fp_pw); close(fp2_pw); /* Rebuild db */ snprintf(line, sizeof(line), "/usr/sbin/pwd_mkdb -p %s", passwd_tmp); system(line); =09 } /* Remove user from the group file and the users group */ void=20 update_group() { char string[BUFSIZ], string2[BUFSIZ], string3[BUFSIZ]; int fp_g, fp2_g, users; char *p, *p2; int a =3D 0; char group[BUFSIZ], gid[BUFSIZ], pass[BUFSIZ], users2[BUFSIZ], users3[BUFS= IZ]; 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 group - = continuing.\n", passwd_file); return; } =09 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 group - = continuing.\n", passwd_tmp); return; } =09 snprintf(string2, sizeof(string2), "%s:", user); while (recvnl(string, fp_g) !=3D -1) { if (strncmp(string, "#", 1) =3D=3D 0) { write(fp2_g, string, strlen(string)); continue; } if (strncasecmp(string, string2, strlen(user) + 1) !=3D 0) { /* Check if user is in the group */ string3[0] =3D '\0'; strlcpy(string3, string, sizeof(string3)); for (p =3D strtok(string3, ":\n"); p !=3D NULL; p =3D strtok(NULL, ":\n"= )) { switch(a) { case 0: strlcpy(group, p, sizeof(group)); break; =09 case 1: strlcpy(pass, p, sizeof(pass)); break; =09 case 2: strlcpy(gid, p, sizeof(gid)); break; =09 case 3: strlcpy(users2, p, sizeof(users2)); break; } a++; =09 } =09 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) { strlcat(users3, p, sizeof(users3)); a =3D 1; } else {=20 strlcat(users3, ",", sizeof(users3)); strlcat(users3, p, sizeof(users3)); } } } =09 snprintf(string3, sizeof(string3), "%s:%s:%s:%s\n", group, pass, gid, us= ers3); =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 section */ *p++; while (*p !=3D ':') *p++; /* Skip gid section */ *p++; strlcpy(string3, p, sizeof(string3)); for (p2 =3D strtok(string3, ","); p2 !=3D NULL; p2 =3D strtok(NULL, ",")= ) { users =3D 1; } =09 if (users =3D=3D 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); */ } } } =09 close(fp_g); close(fp2_g); rename(new_group_file, group_file); } /* Recieve a string from fd untill a \n */ int=20 recvnl(char *buf, int fd) { int bytes =3D 0; char buf2[2]; char buf3[BUFSIZ]; buf3[0] =3D '\0'; while ( read(fd, buf2, 1) !=3D 0) { buf2[1] =3D '\0'; if (strncmp(buf2, "\n", 1) =3D=3D 0) { strncpy(buf, buf3, BUFSIZ); return bytes; } else { strlcat(buf3, buf2, sizeof(buf3)); bytes++; } } =09 return -1; } /* Kill users processes */ void=20 killuser(int uid, int gid) { int pid;=09 =09 if (( pid =3D fork()) =3D=3D 0) { if (setgid(gid) =3D=3D -1) { warn("Warning: Unable to set gid - continuing.\n"); return; } if (setuid(uid) =3D=3D -1) { warn("Warning: Unable to set uid - continuing.\n"); return; } =09 kill(0, SIGTERM); sleep(1); kill(0, SIGKILL); exit(1); } =09 if (pid =3D=3D -1) { warn("Error creating child processes - continuing.\n"); return; } else { while (waitpid(-1,NULL,0) !=3D pid) ; /* Do nothing */ } } void=20 del_mail() { char string[BUFSIZ]; =09 snprintf(string, sizeof(string), "%s/%s", mail_dir, user); if (unlink(string) < 0 && errno !=3D ENOENT) warn("can't remove mailbox: %s", string); =09 } /* Signal handeling */ void=20 sighandle(int sig) { char unknown[] =3D "UNKNOWN", sint[] =3D "SIGINT", squit[] =3D "SIGQUIT"; char shup[] =3D "SIGHUP", sterm[] =3D "SIGTERM"; struct iovec vec[3]; char msg1[] =3D "\nCaught signal ", msg2[] =3D " -- cleaning up\n"; =09 vec[0].iov_base =3D msg1; vec[0].iov_len =3D sizeof(msg1) - 1; vec[2].iov_base =3D msg2; vec[2].iov_len =3D sizeof(msg2) - 1; switch (sig) { case SIGINT: vec[1].iov_base =3D sint; vec[1].iov_len =3D sizeof(sint) - 1; break; case SIGQUIT: vec[1].iov_base =3D squit; vec[1].iov_len =3D sizeof(squit) - 1; break; case SIGTERM: vec[1].iov_base =3D sterm; vec[1].iov_len =3D sizeof(sterm) - 1; break; case SIGHUP: vec[1].iov_base =3D shup; vec[1].iov_len =3D sizeof(shup) - 1; break; default: vec[1].iov_base =3D unknown; vec[1].iov_len =3D sizeof(unknown) - 1; break; } =09 writev(STDOUT_FILENO, vec, sizeof(vec) / sizeof(*vec)); unlink(passwd_tmp); unlink(new_group_file); close(fp); exit(1); } --/9DWx/yDrRhgMJTb-- --U+BazGySraz5kW0T Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.1 (FreeBSD) iD8DBQE9zSlP1JB0Z4PFXt4RAgDRAJ9C5XkSVZfCfcArsOzQzvn/MvcLPQCggD6t DyASnHaHQ9bpcYmY1iSD+6M= =gtCA -----END PGP SIGNATURE----- --U+BazGySraz5kW0T-- 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?20021109152711.GA746>