00001
00002
00003
00004
00005 #include <sys/types.h>
00006 #include <fcntl.h>
00007 #include <string.h>
00008 #include <signal.h>
00009 #include <pwd.h>
00010 #include <errno.h>
00011 #include <stdlib.h>
00012 #include <unistd.h>
00013 #include <time.h>
00014 #include <sys/stat.h>
00015 #include <minix/minlib.h>
00016 #include <stdio.h>
00017
00018 _PROTOTYPE(void report, (char *label));
00019 _PROTOTYPE(void quit, (int ex_stat));
00020 _PROTOTYPE(void fatal, (char *label));
00021 _PROTOTYPE(void usage, (void));
00022 _PROTOTYPE(int goodchars, (char *s));
00023 _PROTOTYPE(int main, (int argc, char **argv));
00024
00025 char pw_file[] = "/etc/passwd";
00026 char sh_file[] = "/etc/shadow";
00027 char pw_tmp[] = "/etc/ptmp";
00028 char bad[] = "Permission denied\n";
00029 char buf[1024];
00030
00031 enum action {
00032 PASSWD, CHFN, CHSH
00033 } action = PASSWD;
00034
00035 char *arg0;
00036
00037 void report(label)
00038 char *label;
00039 {
00040 int e = errno;
00041 fprintf(stderr, "%s: ", arg0);
00042 fflush(stderr);
00043 errno = e;
00044 perror(label);
00045 }
00046
00047 void quit(ex_stat)
00048 int ex_stat;
00049 {
00050 if (unlink(pw_tmp) < 0 && errno != ENOENT) {
00051 report(pw_tmp);
00052 ex_stat = 1;
00053 }
00054 exit(ex_stat);
00055 }
00056
00057 void fatal(label)
00058 char *label;
00059 {
00060 report(label);
00061 quit(1);
00062 }
00063
00064 void usage()
00065 {
00066 static char *usages[] = {
00067 "passwd [user]\n",
00068 "chfn [user] fullname\n",
00069 "chsh [user] shell\n"
00070 };
00071 std_err(usages[(int) action]);
00072 exit(1);
00073 }
00074
00075 int goodchars(s)
00076 char *s;
00077 {
00078 int c;
00079
00080 while ((c = *s++) != 0) {
00081 if (c == ':' || c < ' ' || c >= 127) return(0);
00082 }
00083 return(1);
00084 }
00085
00086 int main(argc, argv)
00087 int argc;
00088 char *argv[];
00089 {
00090 int uid, cn, n;
00091 int fd_pwd, fd_tmp;
00092 FILE *fp_tmp;
00093 time_t salt;
00094 struct passwd *pwd;
00095 char *name, pwname[9], oldpwd[9], newpwd[9], newcrypted[14], sl[2];
00096 char *argn;
00097 int shadow = 0;
00098
00099 if ((arg0 = strrchr(argv[0], '/')) != 0)
00100 arg0++;
00101 else
00102 arg0 = argv[0];
00103
00104 if (strcmp(arg0, "chfn") == 0)
00105 action = CHFN;
00106 else if (strcmp(arg0, "chsh") == 0)
00107 action = CHSH;
00108
00109 uid = getuid();
00110
00111 n = action == PASSWD ? 1 : 2;
00112
00113 if (argc != n && argc != n + 1) usage();
00114
00115 if (argc == n) {
00116 pwd = getpwuid(uid);
00117 strcpy(pwname, pwd->pw_name);
00118 name = pwname;
00119 } else {
00120 name = argv[1];
00121 pwd = getpwnam(name);
00122 }
00123 if (pwd == NULL || ((uid != pwd->pw_uid) && uid != 0)) {
00124 std_err(bad);
00125 exit(1);
00126 }
00127
00128 switch (action) {
00129 case PASSWD:
00130 if (pwd->pw_passwd[0] == '#' && pwd->pw_passwd[1] == '#') {
00131
00132 shadow = 1;
00133 strncpy(pwname, pwd->pw_passwd + 2, 8);
00134 pwname[8] = 0;
00135 name = pwname;
00136 setpwfile(sh_file);
00137 if ((pwd= getpwnam(name)) == NULL) {
00138 std_err(bad);
00139 exit(1);
00140 }
00141 printf("Changing the shadow password of %s\n", name);
00142 } else {
00143 printf("Changing the password of %s\n", name);
00144 }
00145
00146 oldpwd[0] = 0;
00147 if (pwd->pw_passwd[0] != '\0' && uid != 0) {
00148 strcpy(oldpwd, getpass("Old password:"));
00149 if (strcmp(pwd->pw_passwd, crypt(oldpwd, pwd->pw_passwd)) != 0)
00150 {
00151 std_err(bad);
00152 exit(1);
00153 }
00154 }
00155 for (;;) {
00156 strcpy(newpwd, getpass("New password:"));
00157
00158 if (newpwd[0] == '\0')
00159 std_err("Password cannot be null");
00160 else if (strcmp(newpwd, getpass("Retype password:")) != 0)
00161 std_err("Passwords don't match");
00162 else
00163 break;
00164
00165 std_err(", try again\n");
00166 }
00167 time(&salt);
00168 sl[0] = (salt & 077) + '.';
00169 sl[1] = ((salt >> 6) & 077) + '.';
00170 for (cn = 0; cn < 2; cn++) {
00171 if (sl[cn] > '9') sl[cn] += 7;
00172 if (sl[cn] > 'Z') sl[cn] += 6;
00173 }
00174 strcpy(newcrypted, crypt(newpwd, sl));
00175 break;
00176
00177 case CHFN:
00178 case CHSH:
00179 argn = argv[argc - 1];
00180
00181 if (strlen(argn) > (action == CHFN ? 80 : 60) || !goodchars(argn)) {
00182 std_err(bad);
00183 exit(1);
00184 }
00185 }
00186
00187 signal(SIGHUP, SIG_IGN);
00188 signal(SIGINT, SIG_IGN);
00189 signal(SIGQUIT, SIG_IGN);
00190 signal(SIGTERM, SIG_IGN);
00191
00192 umask(0);
00193 n = 10;
00194 while ((fd_tmp = open(pw_tmp, O_RDWR | O_CREAT | O_EXCL, 0400)) < 0) {
00195 if (errno != EEXIST) fatal("Can't create temporary file");
00196
00197 if (n-- > 0) {
00198 sleep(2);
00199 } else {
00200 fprintf(stderr, "Password file busy, try again later.\n");
00201 exit(1);
00202 }
00203 }
00204
00205 if ((fp_tmp = fdopen(fd_tmp, "w+")) == NULL) fatal(pw_tmp);
00206
00207 setpwent();
00208 while ((pwd = getpwent()) != 0) {
00209 if (strcmp(name, pwd->pw_name) == 0) {
00210 switch (action) {
00211 case PASSWD:
00212 pwd->pw_passwd = newcrypted;
00213 break;
00214 case CHFN:
00215 pwd->pw_gecos = argn;
00216 break;
00217 case CHSH:
00218 pwd->pw_shell = argn;
00219 break;
00220 }
00221 }
00222 if (strcmp(pwd->pw_shell, "/bin/sh") == 0
00223 || strcmp(pwd->pw_shell, "/usr/bin/sh") == 0
00224 )
00225 pwd->pw_shell = "";
00226
00227 fprintf(fp_tmp, "%s:%s:%s:",
00228 pwd->pw_name,
00229 pwd->pw_passwd,
00230 itoa(pwd->pw_uid)
00231 );
00232 if (ferror(fp_tmp)) fatal(pw_tmp);
00233
00234 fprintf(fp_tmp, "%s:%s:%s:%s\n",
00235 itoa(pwd->pw_gid),
00236 pwd->pw_gecos,
00237 pwd->pw_dir,
00238 pwd->pw_shell
00239 );
00240 if (ferror(fp_tmp)) fatal(pw_tmp);
00241 }
00242 endpwent();
00243 if (fflush(fp_tmp) == EOF) fatal(pw_tmp);
00244
00245 if (lseek(fd_tmp, (off_t) 0, SEEK_SET) != 0)
00246 fatal("Can't reread temp file");
00247
00248 if ((fd_pwd = open(shadow ? sh_file : pw_file, O_WRONLY | O_TRUNC)) < 0)
00249 fatal("Can't recreate password file");
00250
00251 while ((n = read(fd_tmp, buf, sizeof(buf))) != 0) {
00252 if (n < 0 || write(fd_pwd, buf, n) != n) {
00253 report("Error rewriting password file, tell root!");
00254 exit(1);
00255 }
00256 }
00257 close(fd_tmp);
00258 close(fd_pwd);
00259 quit(0);
00260 }