]>
Commit | Line | Data |
---|---|---|
f0c4fc06 | 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 | RCSID("$Header$"); | |
28 | ||
29 | void usage(void); | |
30 | int chsh(char *uname); | |
31 | int get_shell(int argc, char **argv, void *uname); | |
32 | int get_fmodtime(int argc, char **argv, void *uname); | |
33 | void check_shell(char *shell); | |
34 | #ifndef HAVE_GETUSERSHELL | |
35 | char *getusershell(void); | |
36 | #endif | |
37 | ||
38 | char *whoami; | |
39 | ||
40 | int main(int argc, char *argv[]) | |
41 | { | |
42 | char *uname; | |
43 | ||
44 | if ((whoami = strrchr(argv[0], '/')) == NULL) | |
45 | whoami = argv[0]; | |
46 | else | |
47 | whoami++; | |
48 | ||
49 | if (argc > 2) | |
50 | usage(); | |
51 | ||
52 | if (argc == 2) | |
53 | uname = argv[1]; | |
54 | else | |
55 | { | |
56 | uname = mrcl_krb_user(); | |
57 | if (!uname) | |
58 | exit(1); | |
59 | } | |
60 | ||
61 | exit(chsh(uname)); | |
62 | } | |
63 | ||
64 | int chsh(char *uname) | |
65 | { | |
66 | int status; /* general purpose exit status */ | |
67 | int q_argc; /* argc for mr_query */ | |
68 | char *q_argv[U_END]; /* argv for mr_query */ | |
69 | char *motd; /* determine Moira server status */ | |
70 | ||
71 | int got_one = 0; /* have we got a new shell yet? */ | |
72 | char shell[BUFSIZ]; /* the new shell */ | |
73 | ||
74 | if (mrcl_connect(NULL, "chsh", 2, 1) != MRCL_SUCCESS) | |
75 | exit(1); | |
76 | ||
77 | /* First, do an access check */ | |
78 | ||
79 | q_argv[USH_NAME] = uname; | |
80 | q_argv[USH_SHELL] = "junk"; | |
81 | q_argc = USH_END; | |
82 | ||
83 | if ((status = mr_access("update_user_shell", q_argc, q_argv))) | |
84 | { | |
85 | com_err(whoami, status, "; shell not\nchanged."); | |
86 | exit(2); | |
87 | } | |
88 | ||
89 | printf("Changing login shell for %s.\n", uname); | |
90 | ||
91 | /* Display current information */ | |
92 | ||
93 | q_argv[NAME] = uname; | |
94 | q_argc = NAME + 1; | |
95 | ||
96 | if ((status = mr_query("get_finger_by_login", q_argc, q_argv, | |
97 | get_fmodtime, uname))) | |
98 | { | |
99 | com_err(whoami, status, "while getting user information."); | |
100 | exit(2); | |
101 | } | |
102 | ||
103 | if ((status = mr_query("get_user_account_by_login", q_argc, q_argv, | |
104 | get_shell, uname))) | |
105 | { | |
106 | com_err(whoami, status, "while getting user information."); | |
107 | exit(2); | |
108 | } | |
109 | ||
110 | /* Ask for new shell */ | |
111 | while (!got_one) | |
112 | { | |
113 | printf("New shell: "); | |
114 | if (!fgets(shell, sizeof(shell), stdin)) | |
115 | exit(0); | |
116 | got_one = (strlen(shell) > 1); | |
117 | } | |
118 | ||
119 | shell[strlen(shell) - 1] = 0; /* strip off newline */ | |
120 | ||
121 | /* Make sure we have a valid shell. This routine could exit */ | |
122 | check_shell(shell); | |
123 | ||
124 | /* Change shell */ | |
125 | ||
126 | printf("Changing shell to %s...\n", shell); | |
127 | ||
128 | q_argv[USH_NAME] = uname; | |
129 | q_argv[USH_SHELL] = shell; | |
130 | q_argc = USH_END; | |
131 | if ((status = mr_query("update_user_shell", q_argc, q_argv, NULL, NULL))) | |
132 | { | |
133 | com_err(whoami, status, "while changing shell."); | |
134 | exit(2); | |
135 | } | |
136 | ||
137 | printf("Shell successfully changed.\n"); | |
138 | mr_disconnect(); | |
139 | ||
140 | return 0; | |
141 | } | |
142 | ||
143 | int get_shell(int argc, char **argv, void *uname) | |
144 | { | |
145 | /* We'll just take the first information we get since login names | |
146 | cannot be duplicated in the database. */ | |
147 | ||
148 | if (argc < U_END || strcmp(argv[U_NAME], uname)) | |
149 | { | |
150 | fprintf(stderr, "Some internal error has occurred. Try again.\n"); | |
151 | exit(3); | |
152 | } | |
153 | ||
154 | printf("Current shell for %s is %s.\n", (char *)uname, argv[U_SHELL]); | |
155 | ||
156 | return MR_ABORT; /* Don't pay attention to other matches. */ | |
157 | } | |
158 | ||
159 | int get_fmodtime(int argc, char **argv, void *uname) | |
160 | { | |
161 | /* We'll just take the first information we get since login names | |
162 | cannot be duplicated in the database. */ | |
163 | ||
164 | if (argc < F_END || strcmp(argv[F_NAME], uname)) | |
165 | { | |
166 | fprintf(stderr, "Some internal error has occurred. Try again.\n"); | |
167 | exit(3); | |
168 | } | |
169 | ||
170 | printf("Finger information last changed on %s\n", argv[F_MODTIME]); | |
171 | printf("by user %s with %s.\n", argv[F_MODBY], argv[F_MODWITH]); | |
172 | ||
173 | return MR_ABORT; /* Don't pay attention to other matches. */ | |
174 | } | |
175 | ||
176 | void check_shell(char *shell) | |
177 | { | |
178 | char *valid_shell; | |
179 | int ok = 0; | |
180 | ||
181 | while ((valid_shell = getusershell())) | |
182 | { | |
183 | if (!strcmp(shell, valid_shell)) | |
184 | { | |
185 | ok = 1; | |
186 | break; | |
187 | } | |
188 | else if (!strcmp(shell, 1 + strrchr(valid_shell, '/'))) | |
189 | { | |
190 | ok = 1; | |
191 | strcpy(shell, valid_shell); | |
192 | break; | |
193 | } | |
194 | } | |
195 | ||
196 | if (!ok) | |
197 | { | |
198 | if (shell[0] != '/') | |
199 | { | |
200 | fprintf(stderr, "%s is not a standard shell. ", shell); | |
201 | fprintf(stderr, "You may choose to use a nonstandard\n"); | |
202 | fprintf(stderr, "shell, but you must specify its complete "); | |
203 | fprintf(stderr, "path name.\n"); | |
204 | exit(2); | |
205 | } | |
206 | else if (access(shell, X_OK)) | |
207 | { | |
208 | fprintf(stderr, "%s is not available.\n", shell); | |
209 | exit(2); | |
210 | } | |
211 | else | |
212 | { | |
213 | printf("%s exists but is an unusual choice.\n", shell); | |
214 | printf("Try again if it is not what you wanted.\n"); | |
215 | } | |
216 | } | |
217 | } | |
218 | ||
219 | void usage(void) | |
220 | { | |
221 | fprintf(stderr, "Usage: %s [user]\n", whoami); | |
222 | exit(1); | |
223 | } | |
224 | ||
225 | #ifndef HAVE_GETUSERSHELL | |
226 | #include <sys/param.h> | |
227 | ||
228 | char *getusershell(void) | |
229 | { | |
230 | static FILE *shells = NULL; | |
231 | ||
232 | /* In a sane universe, no shell will have a length longer than | |
233 | * MAXPATHLEN. If any line in /etc/shells does, we'll lose, but | |
234 | * not much. shrug. | |
235 | */ | |
236 | static char buf[MAXPATHLEN]; | |
237 | char *p; | |
238 | ||
239 | if (!shells) | |
240 | { | |
241 | shells = fopen("/etc/shells", "r"); | |
242 | if (!shells) | |
243 | { | |
244 | fprintf(stderr, "%s: Can't open /etc/shells. Unable to determine if " | |
245 | "this is a normal shell.\n\n", whoami); | |
246 | return NULL; | |
247 | } | |
248 | } | |
249 | ||
250 | while (1) | |
251 | { | |
252 | if (!fgets(buf, sizeof(buf), shells)) | |
253 | { | |
254 | fclose(shells); | |
255 | shells = NULL; | |
256 | return NULL; | |
257 | } | |
258 | ||
259 | if (buf[0] != '/') | |
260 | continue; | |
261 | ||
262 | p = strchr(buf, '\n'); | |
263 | if (p) | |
264 | *p = '\0'; | |
265 | ||
266 | return buf; | |
267 | } | |
268 | } | |
269 | #endif |