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