xref: /original-bsd/usr.bin/passwd/chfn.sh (revision 92d3de31)
1#ifndef lint
2static char *sccsid = "@(#)chfn.sh	4.2 (Berkeley) 05/03/83";
3#endif lint
4
5/*
6 *	 changefinger - change finger entries
7 */
8#include <stdio.h>
9#include <signal.h>
10#include <pwd.h>
11
12char	passwd[] = "/etc/passwd";
13char	temp[]	 = "/etc/ptmp";
14struct	passwd *pwd;
15struct	passwd *getpwent(), *getpwnam(), *getpwuid();
16int	endpwent();
17char	*crypt();
18char	*getpass();
19char	buf[BUFSIZ];
20
21#define MAX_STR 52
22main(argc, argv)
23	int argc;
24	char *argv[];
25{
26	int user_uid;
27	int num_bytes, fi, fo;
28	char replacement[4*MAX_STR];
29	FILE *tf;
30
31	if (argc > 2) {
32		printf("Usage: changefinger [user]\n");
33		exit(1);
34	}
35	/*
36	 * Error check to make sure the user (foolishly) typed their own name.
37	 */
38	user_uid = getuid();
39	if ((argc == 2) && (user_uid != 0)) {
40		pwd = getpwnam(argv[1]);
41		if (pwd == NULL) {
42			printf("%s%s%s%s%s%s%s%s",
43				"There is no account for ", argv[1],
44				" on this machine.\n",
45				"You probably mispelled your login name;\n",
46				"only root is allowed to change another",
47				" person's finger entry.\n",
48				"Note:  you do not need to type your login",
49				" name as an argument.\n");
50			exit(1);
51		}
52		if (pwd->pw_uid != user_uid) {
53			printf("%s%s",
54				"You are not allowed to change another",
55				" person's password entry.\n");
56			exit(1);
57		}
58	}
59	/*
60	 * If root is changing a finger entry, then find the uid that
61	 * corresponds to the user's login name.
62	 */
63	if ((argc == 2) && (user_uid == 0)) {
64		pwd = getpwnam(argv[1]);
65		if (pwd == NULL) {
66			printf("There is no account for %s on this machine\n",
67				pwd->pw_name);
68			exit(1);
69		}
70		user_uid = pwd->pw_uid;
71	}
72	/*
73	 * Collect name, room number, school phone, and home phone.
74	 */
75	get_info(replacement);
76	/*
77	 * Update the entry in the password file.
78	 */
79	while (access(temp, 0) >= 0) {
80		printf("Password file busy -- waiting for it to be free.\n");
81		sleep(10);
82	}
83	(void) signal(SIGHUP, SIG_IGN);
84	(void) signal(SIGINT, SIG_IGN);
85	(void) signal(SIGQUIT, SIG_IGN);
86	(void) signal(SIGTSTP, SIG_IGN);
87	/*
88	 * Race condition -- the locking mechinism is not my idea (ns)
89	 */
90	if(access(temp, 0) >= 0) {
91		printf("It's not your day!  Password file is busy again.\n");
92		printf("Try again later.\n");
93		exit(1);
94	}
95	if((tf=fopen(temp,"w")) == NULL) {
96		printf("Cannot create temporary file\n");
97		exit(1);
98	}
99	/*
100	 * There is another race condition here:  if the passwd file
101	 * has changed since the error checking at the beginning of the program,
102	 * then user_uid may not be in the file.  Of course, the uid might have
103	 * been changed, but this is not supposed to happen.
104	 */
105	if (getpwuid(user_uid) == NULL) {
106		printf("%s%d%s\n", "Passwd file has changed. Uid ", user_uid,
107			" is no longer in the file!?");
108		goto out;
109	}
110	/*
111	 * copy passwd to temp, replacing matching line
112	 * with new finger entry (gecos field).
113	 */
114	while((pwd=getpwent()) != NULL) {
115		if(pwd->pw_uid == user_uid) {
116			pwd->pw_gecos = replacement;
117		}
118		fprintf(tf,"%s:%s:%d:%d:%s:%s:%s\n",
119			pwd->pw_name,
120			pwd->pw_passwd,
121			pwd->pw_uid,
122			pwd->pw_gid,
123			pwd->pw_gecos,
124			pwd->pw_dir,
125			pwd->pw_shell);
126	}
127	(void) endpwent();
128	(void) fclose(tf);
129	/*
130	 * Copy temp back to password file.
131	 */
132	if((fi=open(temp,0)) < 0) {
133		printf("Temp file disappeared!\n");
134		goto out;
135	}
136	if((fo=creat(passwd, 0644)) < 0) {
137		printf("Cannot recreat passwd file.\n");
138		goto out;
139	}
140	while((num_bytes=read(fi,buf,sizeof(buf))) > 0)
141		(void) write(fo,buf,num_bytes);
142out:
143	(void) unlink(temp);
144}
145
146/*
147 * Get name, room number, school phone, and home phone.
148 */
149get_info(answer)
150	char *answer;
151{
152	char *strcpy(), *strcat();
153	char in_str[MAX_STR];
154	answer[0] = '\0';
155
156	/*
157	 * Get name.
158	 */
159	do {
160		printf("\nName: ");
161		(void) fgets(in_str, MAX_STR, stdin);
162	} while (illegal_input(in_str));
163	(void) strcpy(answer, in_str);
164	/*
165	 * Get room number.
166	 */
167	do {
168		printf("Room number (Exs: 597E or 197C): ");
169		(void) fgets(in_str, MAX_STR, stdin);
170	} while (illegal_input(in_str) || illegal_building(in_str));
171	(void) strcat(strcat(answer, ","), in_str);
172	/*
173	 * Get office phone number.
174	 * Remove hyphens and 642 or x2 prefixes if present.
175	 */
176	do {
177		printf("Office Phone (Ex: 1632): ");
178		(void) fgets(in_str, MAX_STR, stdin);
179		remove_hyphens(in_str);
180		if ((strlen(in_str) == 8) && (strcmpn(in_str, "642", 3) == 0))
181			(void) strcpy(in_str, in_str+3);
182		if ((strlen(in_str) == 7) && (strcmpn(in_str, "x2", 2) == 0))
183			(void) strcpy(in_str, in_str+2);
184	} while ((illegal_input(in_str)) || wrong_length(in_str, 4));
185	(void) strcat(strcat(answer, ","), in_str);
186	/*
187	 * Get home phone number.
188	 * Remove hyphens if present.
189	 */
190	do {
191		printf("Home Phone (Ex: 9875432): ");
192		(void) fgets(in_str, MAX_STR, stdin);
193		remove_hyphens(in_str);
194	} while (illegal_input(in_str));
195	(void) strcat(strcat(answer, ","), in_str);
196}
197
198/*
199 * Prints an error message if a ':' or a newline is found in the string.
200 * A message is also printed if the input string is too long.
201 * The password file uses :'s as seperators, and are not allowed in the "gcos"
202 * field.  Newlines serve a delimiters between users in the password file,
203 * and so, those too, are checked for.  (I don't think that it is possible to
204 * type them in, but better safe than sorry)
205 *
206 * Returns '1' if a colon or newline is found or the input line is too long.
207 */
208illegal_input(input_str)
209	char *input_str;
210{
211	char *index();
212	char *ptr;
213	int error_flag = 0;
214	int length = strlen(input_str);
215
216	if (index(input_str, ':')) {
217		printf("':' is not allowed.\n");
218		error_flag = 1;
219	}
220	if (input_str[length-1] != '\n') {
221		/* the newline and the '\0' eat up two characters */
222		printf("Maximum number of characters allowed is %d\n",
223			MAX_STR-2);
224		/* flush the rest of the input line */
225		while (getchar() != '\n')
226			/* void */;
227		error_flag = 1;
228	}
229	/*
230	 * Delete newline by shortening string by 1.
231	 */
232	input_str[length-1] = '\0';
233	/*
234	 * Don't allow control characters, etc in input string.
235	 */
236	for (ptr=input_str; *ptr != '\0'; ptr++) {
237		if ((int) *ptr < 040) {
238			printf("Control characters are not allowed.\n");
239			error_flag = 1;
240			break;
241		}
242	}
243	return(error_flag);
244}
245
246/*
247 * Removes '-'s from the input string.
248 */
249remove_hyphens(str)
250	char *str;
251{
252	char *hyphen, *index(), *strcpy();
253
254	while ((hyphen=index(str, '-')) != NULL) {
255		(void) strcpy(hyphen, hyphen+1);
256	}
257}
258
259/*
260 * Returns 1 when the length of the input string is not zero or equal to n.
261 * Prints an error message in this case.
262 */
263wrong_length(str, n)
264	char *str;
265	int n;
266{
267	if ((strlen(str) != 0) && (strlen(str) != n)) {
268		printf("The phone number should be %d digits long.\n", n);
269		return(1);
270	}
271	return(0);
272}
273
274/*
275 * Make sure that building is 'E' or 'C'.
276 * Error correction is done if building is 'e', 'c', "evans", or "cory".
277 * Correction changes "str".
278 * The finger program determines the building by looking at the last
279 * character.  Currently, finger only allows that character to be 'E' or 'C'.
280 *
281 * Returns 1 if incorrect room format.
282 *
283 * Note: this function assumes that the newline has been removed from str.
284 */
285illegal_building(str)
286	char *str;
287{
288	int length = strlen(str);
289	char *last_ch, *ptr;
290
291	/*
292	 * Zero length strings are acceptable input.
293	 */
294	if (length == 0)
295		return(0);
296	/*
297	 * Delete "vans" and "ory".
298	 */
299	if (strcmpn(str+length-4, "vans", 4) == 0) {
300		length -= 4;
301		str[length] = '\0';
302	}
303	if (strcmpn(str+length-3, "ory", 3) == 0) {
304		length -= 3;
305		str[length] = '\0';
306	}
307	last_ch = str+length-1;
308	/*
309	 * Now change e to E or c to C.
310	 */
311	if (*last_ch == 'e')
312		*last_ch = 'E';
313	if (*last_ch == 'c')
314		*last_ch = 'C';
315	/*
316	 * Delete any spaces before the E or C.
317	 */
318	for (ptr=last_ch-1; ptr>str; ptr--) {
319		if (*ptr != ' ')
320			break;
321	}
322	(void) strcpy(ptr+1, last_ch);
323	/*
324	 * Make sure building is evans or cory.
325	 */
326	if ((*last_ch != 'E') && (*last_ch != 'C')) {
327		printf("%s%s%s",
328			"The finger program requires that your",
329			" office be in Cory or Evans.\n",
330			"Enter this as (for example) 597E or 197C.\n");
331		return(1);
332	}
333	return(0);
334}
335