]>
Commit | Line | Data |
---|---|---|
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 | ||
29 | RCSID("$Header$"); | |
30 | ||
31 | void usage(void); | |
32 | int get_shell(int argc, char **argv, void *username); | |
33 | int get_winshell(int argc, char **argv, void *username); | |
34 | int get_fmodtime(int argc, char **argv, void *username); | |
35 | void check_shell(char *shell); | |
36 | #ifndef HAVE_GETUSERSHELL | |
37 | char *getusershell(void); | |
38 | #endif | |
39 | ||
40 | char *whoami; | |
41 | char *username; | |
42 | ||
43 | int 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", 12, 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 | ||
208 | int 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 | ||
224 | int 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 | ||
241 | int 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 | ||
258 | void 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 | ||
301 | void 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 | ||
310 | char *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 |