Commit | Line | Data |
---|---|---|
9f52e30a | 1 | #ifndef lint |
01eaadf6 | 2 | static char *sccsid = "@(#)chsh.sh 4.9 (Berkeley) %G%"; |
9f52e30a SL |
3 | #endif |
4 | ||
854c8e85 BJ |
5 | /* |
6 | * chsh | |
7 | */ | |
8 | #include <stdio.h> | |
9 | #include <signal.h> | |
10 | #include <pwd.h> | |
01eaadf6 | 11 | #include <ndbm.h> |
9f52e30a | 12 | #include <sys/file.h> |
840fc587 SL |
13 | #include <sys/time.h> |
14 | #include <sys/resource.h> | |
854c8e85 | 15 | |
a7da04e0 | 16 | char temp[] = "/etc/ptmp"; |
854c8e85 | 17 | char passwd[] = "/etc/passwd"; |
854c8e85 BJ |
18 | struct passwd *pwd; |
19 | struct passwd *getpwent(); | |
20 | int endpwent(); | |
21 | char *crypt(); | |
22 | char *getpass(); | |
9f52e30a | 23 | char *strcat(); |
854c8e85 BJ |
24 | char buf[BUFSIZ]; |
25 | ||
26 | main(argc, argv) | |
9f52e30a | 27 | register char *argv[]; |
854c8e85 | 28 | { |
9f52e30a SL |
29 | register int u, fd; |
30 | register FILE *tf; | |
01eaadf6 | 31 | DBM *dp; |
854c8e85 | 32 | |
9f52e30a | 33 | if (argc < 2 || argc > 3) { |
1f096eb2 | 34 | printf("Usage: chsh user [ /bin/csh ]\n"); |
9f52e30a | 35 | exit(1); |
854c8e85 BJ |
36 | } |
37 | if (argc == 2) | |
38 | argv[2] = ""; | |
9f52e30a SL |
39 | else { |
40 | if (argv[2][0] != '/') | |
41 | argv[2] = strcat( | |
42 | "/bin/\0 12345678901234567890123456789", argv[2]); | |
43 | if (strcmp(argv[2], "/bin/csh") && | |
44 | strcmp(argv[2], "/bin/oldcsh") && | |
45 | strcmp(argv[2], "/bin/newcsh") && | |
46 | strcmp(argv[2], "/usr/new/csh") && | |
47 | /* and, for cretins who can't read the manual */ | |
48 | strcmp(argv[2], "/bin/sh") && | |
49 | getuid()) { | |
50 | printf( | |
51 | "Only /bin/csh may be specified\n" | |
52 | ); | |
78ffcf9e BJ |
53 | exit(1); |
54 | } | |
9f52e30a SL |
55 | if (access(argv[2], 1) < 0) { |
56 | printf("%s is not available\n", argv[2]); | |
57 | exit(1); | |
58 | } | |
59 | } | |
60 | unlimit(RLIMIT_CPU); | |
61 | unlimit(RLIMIT_FSIZE); | |
a7da04e0 RC |
62 | u = getuid(); |
63 | if (u != 0 && ((pwd = getpwnam(argv[1])) == NULL || u != pwd->pw_uid)) { | |
64 | printf("Permission denied.\n"); | |
65 | exit(1); | |
9f52e30a | 66 | } |
854c8e85 | 67 | |
9f52e30a SL |
68 | signal(SIGHUP, SIG_IGN); |
69 | signal(SIGINT, SIG_IGN); | |
70 | signal(SIGQUIT, SIG_IGN); | |
71 | signal(SIGTSTP, SIG_IGN); | |
fb8f0ff2 | 72 | (void) umask(0); |
9f52e30a | 73 | if ((fd = open(temp, O_CREAT|O_EXCL|O_RDWR, 0644)) < 0) { |
854c8e85 | 74 | printf("Temporary file busy -- try again\n"); |
9f52e30a | 75 | exit(1); |
854c8e85 | 76 | } |
01eaadf6 | 77 | if ((tf = fdopen(fd, "w")) == NULL) { |
9f52e30a SL |
78 | printf("Absurd fdopen failure - seek help\n"); |
79 | goto out; | |
854c8e85 | 80 | } |
01eaadf6 RC |
81 | if ((dp = ndbmopen(passwd, O_RDWR, 0644)) == NULL) { |
82 | fprintf(stderr, "Warning: dbminit failed: "); | |
83 | perror(passwd); | |
84 | } else if (flock(dp->db_dirf, LOCK_EX) < 0) { | |
85 | perror("Warning: lock failed"); | |
86 | ndbmclose(dp); | |
87 | dp = NULL; | |
88 | } | |
9f52e30a SL |
89 | /* |
90 | * Copy passwd to temp, replacing matching lines | |
91 | * with new shell. | |
92 | */ | |
01eaadf6 | 93 | while ((pwd = getpwent()) != NULL) { |
9f52e30a | 94 | if (strcmp(pwd->pw_name, argv[1]) == 0) { |
9f52e30a | 95 | if (u != 0 && u != pwd->pw_uid) { |
854c8e85 BJ |
96 | printf("Permission denied.\n"); |
97 | goto out; | |
98 | } | |
99 | pwd->pw_shell = argv[2]; | |
01eaadf6 | 100 | replace(dp, pwd); |
854c8e85 | 101 | } |
9f52e30a SL |
102 | if (strcmp(pwd->pw_shell, "/bin/sh") == 0) |
103 | pwd->pw_shell = ""; | |
104 | fprintf(tf, "%s:%s:%d:%d:%s:%s:%s\n" | |
105 | , pwd->pw_name | |
106 | , pwd->pw_passwd | |
107 | , pwd->pw_uid | |
108 | , pwd->pw_gid | |
109 | , pwd->pw_gecos | |
110 | , pwd->pw_dir | |
111 | , pwd->pw_shell | |
112 | ); | |
854c8e85 BJ |
113 | } |
114 | endpwent(); | |
01eaadf6 RC |
115 | (void) fclose(tf); |
116 | ndbmclose(dp); | |
117 | if (rename(temp, passwd) < 0) { | |
a7da04e0 | 118 | fprintf(stderr, "chsh: "), perror("rename"); |
01eaadf6 RC |
119 | out: |
120 | (void) unlink(temp); | |
121 | exit(1); | |
122 | } | |
123 | exit(0); | |
9f52e30a | 124 | } |
854c8e85 | 125 | |
9f52e30a SL |
126 | unlimit(lim) |
127 | { | |
128 | struct rlimit rlim; | |
854c8e85 | 129 | |
9f52e30a SL |
130 | rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; |
131 | setrlimit(lim, &rlim); | |
854c8e85 | 132 | } |
a7da04e0 | 133 | |
01eaadf6 RC |
134 | /* |
135 | * Replace the password entry in the dbm data base with pwd. | |
136 | */ | |
137 | replace(dp, pwd) | |
138 | DBM *dp; | |
139 | struct passwd *pwd; | |
a7da04e0 | 140 | { |
01eaadf6 RC |
141 | datum key, content; |
142 | register char *cp, *tp; | |
143 | char buf[BUFSIZ]; | |
a7da04e0 | 144 | |
01eaadf6 RC |
145 | if (dp == NULL) |
146 | return; | |
147 | ||
148 | cp = buf; | |
149 | #define COMPACT(e) tp = pwd->pw_/**/e; while (*cp++ = *tp++); | |
150 | COMPACT(name); | |
151 | COMPACT(passwd); | |
152 | *(int *)cp = pwd->pw_uid; cp += sizeof (int); | |
153 | *(int *)cp = pwd->pw_gid; cp += sizeof (int); | |
154 | *(int *)cp = pwd->pw_quota; cp += sizeof (int); | |
155 | COMPACT(comment); | |
156 | COMPACT(gecos); | |
157 | COMPACT(dir); | |
158 | COMPACT(shell); | |
159 | content.dptr = buf; | |
160 | content.dsize = cp - buf; | |
161 | key.dptr = pwd->pw_name; | |
162 | key.dsize = strlen(pwd->pw_name); | |
163 | dbmstore(dp, key, content, DB_REPLACE); | |
164 | key.dptr = (char *)&pwd->pw_uid; | |
165 | key.dsize = sizeof (int); | |
166 | dbmstore(dp, key, content, DB_REPLACE); | |
a7da04e0 | 167 | } |