]> andersk Git - moira.git/blame_incremental - clients/chsh/chsh.c
Fix double-free that makes RHEL4 unhappy if you ctrl-c at the wrong time.
[moira.git] / clients / chsh / chsh.c
... / ...
CommitLineData
1/* $Id$
2 *
3 * Talk to the Moira database to change a person's login shell. The chosen
4 * shell must exist. A warning will be issued if the shell is not in
5 * /etc/shells.
6 *
7 * chsh with no modifiers changes the shell of the user who is running
8 * the program.
9 *
10 * If a commandline argument is given, it is taken to be the username
11 * of the user whose shell is to be changed.
12 *
13 * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology
14 * For copying and distribution information, please see the file
15 * <mit-copyright.h>.
16 */
17
18#include <mit-copyright.h>
19#include <moira.h>
20#include <moira_site.h>
21#include <mrclient.h>
22
23#include <stdio.h>
24#include <string.h>
25#include <unistd.h>
26
27#define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b))
28
29RCSID("$Header$");
30
31void usage(void);
32int get_shell(int argc, char **argv, void *username);
33int get_winshell(int argc, char **argv, void *username);
34int get_fmodtime(int argc, char **argv, void *username);
35void check_shell(char *shell);
36#ifndef HAVE_GETUSERSHELL
37char *getusershell(void);
38#endif
39
40char *whoami;
41char *username;
42
43int main(int argc, char *argv[])
44{
45 int status; /* general purpose exit status */
46 int q_argc; /* argc for mr_query */
47 char *q_argv[U_END]; /* argv for mr_query */
48 char *motd; /* determine Moira server status */
49 int got_one = 0; /* Have we got a shell yet? */
50 char shell[BUFSIZ]; /* Our new shell */
51 int windowsflg = 0, unixflg = 0;
52 char **arg = argv;
53 char *server = NULL;
54
55 if ((whoami = strrchr(argv[0], '/')) == NULL)
56 whoami = argv[0];
57 else
58 whoami++;
59
60 /* parse our command line options */
61 while (++arg - argv < argc)
62 {
63 if (**arg == '-')
64 {
65 if (argis("w", "winshell"))
66 windowsflg++;
67 else if (argis("u", "unixshell"))
68 unixflg++;
69 else if (argis("db", "database"))
70 {
71 if (arg - argv < argc - 1)
72 {
73 ++arg;
74 server = *arg;
75 }
76 else
77 usage();
78 }
79 }
80 else if (username == NULL)
81 username = *arg;
82 else
83 usage();
84 }
85
86 if (!username)
87 {
88 username = mrcl_krb_user();
89 if (!username)
90 exit(1);
91 }
92
93 if (!unixflg && !windowsflg)
94 unixflg++;
95
96 if (unixflg && windowsflg)
97 usage();
98
99 if (mrcl_connect(server, "chsh", 3, 1) != MRCL_SUCCESS)
100 exit(1);
101
102 /* First, do an access check */
103
104 q_argv[USH_NAME] = username;
105 q_argv[USH_SHELL] = "junk";
106 q_argc = USH_END;
107
108 if ((status = mr_access("update_user_shell", q_argc, q_argv)))
109 {
110 com_err(whoami, status, "; shell not\nchanged.");
111 exit(2);
112 }
113
114 printf("Changing login shell for %s.\n", username);
115
116 /* Display current information */
117
118 q_argv[NAME] = username;
119 q_argc = NAME + 1;
120
121 if ((status = mr_query("get_finger_by_login", q_argc, q_argv,
122 get_fmodtime, username)))
123 {
124 com_err(whoami, status, "while getting user information.");
125 exit(2);
126 }
127
128 if (unixflg)
129 {
130 if ((status = mr_query("get_user_account_by_login", q_argc, q_argv,
131 get_shell, username)))
132 {
133 com_err(whoami, status, "while getting user information.");
134 exit(2);
135 }
136
137 /* Ask for new shell */
138 while (!got_one)
139 {
140 printf("New shell: ");
141 if (!fgets(shell, sizeof(shell), stdin))
142 exit(0);
143 got_one = (strlen(shell) > 1);
144 }
145
146 shell[strlen(shell) - 1] = 0; /* strip off newline */
147
148 /* Make sure we have a valid shell. This routine could exit */
149 check_shell(shell);
150
151 /* Change shell */
152
153 printf("Changing shell to %s...\n", shell);
154
155 q_argv[USH_NAME] = username;
156 q_argv[USH_SHELL] = shell;
157 q_argc = USH_END;
158 if ((status = mr_query("update_user_shell", q_argc, q_argv, NULL, NULL)))
159 {
160 com_err(whoami, status, "while changing shell.");
161 exit(2);
162 }
163
164 printf("Shell successfully changed.\n");
165 }
166 else if (windowsflg)
167 {
168 if ((status = mr_query("get_user_account_by_login", q_argc, q_argv,
169 get_winshell, username)))
170 {
171 com_err(whoami, status, "while getting user information.");
172 exit(2);
173 }
174
175 /* Ask for new Windows shell */
176 while(!got_one)
177 {
178 printf("New Windows shell: ");
179 if (!fgets(shell, sizeof(shell), stdin))
180 exit(0);
181 got_one = (strlen(shell) > 1);
182 }
183
184 shell[strlen(shell) - 1] = 0; /* strip off newline */
185
186 /* Change shell */
187
188 printf("Changing Windows shell to %s...\n", shell);
189
190 q_argv[USH_NAME] = username;
191 q_argv[USH_SHELL] = shell;
192 q_argc = USH_END;
193 if ((status = mr_query("update_user_windows_shell", q_argc, q_argv,
194 NULL, NULL)))
195 {
196 com_err(whoami, status, "while changing Windows shell.");
197 exit(2);
198 }
199
200 printf("Windows shell successfully changed.\n");
201 }
202
203 mr_disconnect();
204
205 return 0;
206}
207
208int get_shell(int argc, char **argv, void *username)
209{
210 /* We'll just take the first information we get since login names
211 cannot be duplicated in the database. */
212
213 if (argc < U_END || strcmp(argv[U_NAME], username))
214 {
215 fprintf(stderr, "Some internal error has occurred. Try again.\n");
216 exit(3);
217 }
218
219 printf("Current shell for %s is %s.\n", (char *)username, argv[U_SHELL]);
220
221 return MR_ABORT; /* Don't pay attention to other matches. */
222}
223
224int get_winshell(int argc, char **argv, void *username)
225{
226 /* We'll just take the first information we get since login names
227 cannot be duplicated in the database. */
228
229 if (argc < U_END || strcmp(argv[U_NAME], username))
230 {
231 fprintf(stderr, "Some internal error has occurred. Try again.\n");
232 exit(3);
233 }
234
235 printf("Current Windows shell for %s is %s.\n", (char *)username,
236 argv[U_WINCONSOLESHELL]);
237
238 return MR_ABORT; /* Don't pay attention to other matches. */
239}
240
241int get_fmodtime(int argc, char **argv, void *username)
242{
243 /* We'll just take the first information we get since login names
244 cannot be duplicated in the database. */
245
246 if (argc < F_END || strcmp(argv[F_NAME], username))
247 {
248 fprintf(stderr, "Some internal error has occurred. Try again.\n");
249 exit(3);
250 }
251
252 printf("Finger information last changed on %s\n", argv[F_MODTIME]);
253 printf("by user %s with %s.\n", argv[F_MODBY], argv[F_MODWITH]);
254
255 return MR_ABORT; /* Don't pay attention to other matches. */
256}
257
258void check_shell(char *shell)
259{
260 char *valid_shell;
261 int ok = 0;
262
263 while ((valid_shell = (char *)getusershell()))
264 {
265 if (!strcmp(shell, valid_shell))
266 {
267 ok = 1;
268 break;
269 }
270 else if (!strcmp(shell, 1 + strrchr(valid_shell, '/')))
271 {
272 ok = 1;
273 strcpy(shell, valid_shell);
274 break;
275 }
276 }
277
278 if (!ok)
279 {
280 if (shell[0] != '/')
281 {
282 fprintf(stderr, "%s is not a standard shell. ", shell);
283 fprintf(stderr, "You may choose to use a nonstandard\n");
284 fprintf(stderr, "shell, but you must specify its complete ");
285 fprintf(stderr, "path name.\n");
286 exit(2);
287 }
288 else if (access(shell, X_OK))
289 {
290 fprintf(stderr, "%s is not available.\n", shell);
291 exit(2);
292 }
293 else
294 {
295 printf("%s exists but is an unusual choice.\n", shell);
296 printf("Try again if it is not what you wanted.\n");
297 }
298 }
299}
300
301void usage(void)
302{
303 fprintf(stderr, "Usage: %s [-w|-u] [user]\n", whoami);
304 exit(1);
305}
306
307#ifndef HAVE_GETUSERSHELL
308#include <sys/param.h>
309
310char *getusershell(void)
311{
312 static FILE *shells = NULL;
313
314 /* In a sane universe, no shell will have a length longer than
315 * MAXPATHLEN. If any line in /etc/shells does, we'll lose, but
316 * not much. shrug.
317 */
318 static char buf[MAXPATHLEN];
319 char *p;
320
321 if (!shells)
322 {
323 shells = fopen("/etc/shells", "r");
324 if (!shells)
325 {
326 fprintf(stderr, "%s: Can't open /etc/shells. Unable to determine if "
327 "this is a normal shell.\n\n", whoami);
328 return NULL;
329 }
330 }
331
332 while (1)
333 {
334 if (!fgets(buf, sizeof(buf), shells))
335 {
336 fclose(shells);
337 shells = NULL;
338 return NULL;
339 }
340
341 if (buf[0] != '/')
342 continue;
343
344 p = strchr(buf, '\n');
345 if (p)
346 *p = '\0';
347
348 return buf;
349 }
350}
351#endif
This page took 0.034904 seconds and 5 git commands to generate.