]> andersk Git - moira.git/blob - clients/passwd/chsh.c
06833b04dcad460e582d044c90b6376c27ff478a
[moira.git] / clients / passwd / chsh.c
1 /*
2  * Copyright 1988 by the Massachusetts Institute of Technology. For copying
3  * and distribution information, see the file "mit-copyright.h".
4  *
5  * $Source$
6  * $Header$
7  * $Author$
8  *
9  */
10
11 #ifndef lint
12 static char *rcsid_chsh_c = "$Header$";
13 #endif
14
15 /*
16  * Talk to the MOIRA database to change a person's login shell.  The chosen
17  * shell must exist.  A warning will be issued if the shell is not in
18  * /etc/shells.
19  *
20  * chsh with no modifiers changes the shell of the user who is running
21  * the program.
22  *
23  * If a commandline argument is given, it is taken to be the username
24  * of the user whose shell is to be changed.
25  *
26  */
27
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/file.h>
33 #include <krb.h>
34 #include <ctype.h>
35 #include <errno.h>
36
37 /* MOIRA includes */
38 #include <moira.h>
39 #include <moira_site.h>
40 #include "mit-copyright.h"
41
42 char *whoami;
43 char *getusershell();
44
45 int main(int argc, char *argv[])
46 {
47   char pname[ANAME_SZ];
48   char *uname = pname;
49   int k_errno;
50
51   initialize_krb_error_table();
52
53   if ((whoami = strrchr(argv[0], '/')) == NULL)
54     whoami = argv[0];
55   else
56     whoami++;
57
58   if (argc > 2)
59     usage();
60
61   if (argc == 2)
62     uname = argv[1];
63   else
64     {
65       /* Do it right; get name from kerberos ticket file rather than
66          from passord file. */
67
68       if ((k_errno = tf_init(TKT_FILE, R_TKT_FIL)))
69         {
70           com_err(whoami, k_errno, "reading ticket file");
71           exit(1);
72         }
73
74       if ((k_errno = tf_get_pname(pname)))
75         {
76           com_err(whoami, k_errno, "getting kerberos principal name");
77           exit(1);
78         }
79
80       tf_close();
81     }
82
83   exit(chsh(uname));
84 }
85
86 /* This should be called rather than exit once connection to moira server
87    has been established. */
88 int leave(int status)
89 {
90   mr_disconnect();
91   exit(status);
92 }
93
94 int scream(void)
95 {
96   com_err(whoami, 0, "Unexpected return value from Moira -- programmer botch");
97   leave(1);
98 }
99
100 int chsh(char *uname)
101 {
102   int status;                   /* general purpose exit status */
103   int q_argc;                   /* argc for mr_query */
104   char *q_argv[U_END];          /* argv for mr_query */
105   char *motd;                   /* determine MR server status */
106
107   int got_one = 0;              /* have we got a new shell yet? */
108   char shell[BUFSIZ];           /* the new shell */
109   int get_shell();
110   void check_shell();           /* make sure new shell is valid */
111
112   /* Try each query.  If we ever fail, print error message and exit. */
113
114   status = mr_connect(NULL);
115   if (status)
116     {
117       com_err(whoami, status, " while connecting to Moira");
118       exit(1);
119     }
120
121   status = mr_motd(&motd);
122   if (status)
123     {
124       com_err(whoami, status, " unable to check server status");
125       leave(1);
126     }
127   if (motd)
128     {
129       fprintf(stderr, "The Moira server is currently unavailable:\n%s\n",
130               motd);
131       leave(1);
132     }
133
134   status = mr_auth("chsh");     /* Don't use argv[0] - too easy to fake */
135   if (status)
136     {
137       com_err(whoami, status,
138               " while authenticating -- run \"kinit\" and try again.");
139       leave(1);
140     }
141
142   /* First, do an access check */
143
144   q_argv[USH_NAME] = uname;
145   q_argv[USH_SHELL] = "junk";
146   q_argc = USH_END;
147
148   if ((status = mr_access("update_user_shell", q_argc, q_argv)))
149     {
150       com_err(whoami, status, "; shell not\nchanged.");
151       leave(2);
152     }
153
154   printf("Changing login shell for %s.\n", uname);
155
156   /* Display current information */
157
158   q_argv[NAME] = uname;
159   q_argc = NAME + 1;
160
161   if ((status = mr_query("get_user_account_by_login", q_argc, q_argv,
162                          get_shell, (char *) uname)))
163     {
164       com_err(whoami, status, " while getting user information.");
165       leave(2);
166     }
167
168   /* Ask for new shell */
169   while (!got_one)
170     {
171       printf("New shell: ");
172       if (!fgets(shell, sizeof(shell), stdin))
173         leave(0);
174       got_one = (strlen(shell) > 1);
175     }
176
177   shell[strlen(shell) - 1] = 0; /* strip off newline */
178
179   /* Make sure we have a valid shell.  This routine could exit */
180   check_shell(shell);
181
182   /* Change shell */
183
184   printf("Changing shell to %s...\n", shell);
185
186   q_argv[USH_NAME] = uname;
187   q_argv[USH_SHELL] = shell;
188   q_argc = USH_END;
189   if ((status = mr_query("update_user_shell", q_argc, q_argv,
190                          scream, NULL)))
191     {
192       com_err(whoami, status, " while changing shell.");
193       leave(2);
194     }
195
196   printf("Shell successfully changed.\n");
197   mr_disconnect();
198
199   return 0;
200 }
201
202 int get_shell(int argc, char **argv, char *uname)
203 {
204   /* We'll just take the first information we get since login names
205      cannot be duplicated in the database. */
206
207   if (argc < U_END || strcmp(argv[U_NAME], uname))
208     {
209       fprintf(stderr, "Some internal error has occurred.  Try again.\n");
210       leave(3);
211     }
212
213   printf("Account information last changed on %s\n", argv[U_MODTIME]);
214   printf("by user %s with %s.\n", argv[U_MODBY], argv[U_MODWITH]);
215   printf("Current shell for %s is %s.\n", uname, argv[U_SHELL]);
216
217   return MR_ABORT;              /* Don't pay attention to other matches. */
218 }
219
220 void check_shell(char *shell)
221 {
222   char *valid_shell;
223   int ok = 0;
224
225   while ((valid_shell = getusershell()))
226     {
227       if (!strcmp(shell, valid_shell))
228         {
229           ok = 1;
230           break;
231         }
232       else if (!strcmp(shell, 1 + strrchr(valid_shell, '/')))
233         {
234           ok = 1;
235           strcpy(shell, valid_shell);
236           break;
237         }
238     }
239
240   if (!ok)
241     {
242       if (shell[0] != '/')
243         {
244           fprintf(stderr, "%s is not a standard shell.  ", shell);
245           fprintf(stderr, "You may choose to use a nonstandard\n");
246           fprintf(stderr, "shell, but you must specify its complete ");
247           fprintf(stderr, "path name.\n");
248           leave(2);
249         }
250       else if (access(shell, X_OK))
251         {
252           fprintf(stderr, "%s is not available.\n", shell);
253           leave(2);
254         }
255       else
256         {
257           printf("%s exists but is an unusual choice.\n", shell);
258           printf("Try again if it is not what you wanted.\n");
259         }
260     }
261 }
262
263 int usage(void)
264 {
265   fprintf(stderr, "Usage: %s [user]\n", whoami);
266   exit(1);
267 }
268
269 #ifdef NEED_GETUSERSHELL
270 char *getusershell()
271 {
272   static int count = 1;
273
274   switch (count++)
275     {
276     case 1:
277       return "/bin/sh";
278     case 2:
279       return "/bin/csh";
280     case 3:
281       return "/bin/athena/tcsh";
282     case 4:
283       return NULL;
284     default:
285       count = 1;
286       return getusershell();
287     }
288 }
289 #endif
This page took 0.814639 seconds and 3 git commands to generate.