]> andersk Git - moira.git/blob - clients/passwd/chsh.c
From mbarker: Remove the `char *whoami;' local to main so that it's
[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
55     initialize_krb_error_table();
56
57     if ((whoami = strrchr(argv[0], '/')) == NULL)
58         whoami = argv[0];
59     else
60         whoami++;
61
62     if (argc > 2) {
63         usage();
64     }
65     
66     if (argc == 2)
67         uname = argv[1];
68     else
69     {
70         /* Do it right; get name from kerberos ticket file rather than 
71            from passord file. */
72         
73         if (k_errno = tf_init(TKT_FILE, R_TKT_FIL)) {
74             com_err(whoami, k_errno, "reading ticket file");
75             exit(1);
76         }
77         
78         if (k_errno = tf_get_pname(pname)) {
79             com_err(whoami, k_errno, "getting kerberos principal name");
80             exit(1);
81         }
82
83         tf_close();
84     }
85     
86     exit(chsh(uname));
87 }
88
89 leave(status)
90   int status;
91   /* This should be called rather than exit once connection to moira server
92      has been established. */
93 {
94     mr_disconnect();
95     exit(status);
96 }
97
98 scream()
99 {
100     com_err(whoami, 0, "Unexpected return value from Moira -- programmer botch");
101     leave(1);
102 }
103
104 chsh(uname)
105   char *uname;
106 {
107     int status;                 /* general purpose exit status */
108     int q_argc;                 /* argc for mr_query */
109     char *q_argv[U_END];        /* argv for mr_query */
110     char *motd;                 /* determine MR server status */
111
112     int got_one = 0;            /* have we got a new shell yet? */
113     char shell[BUFSIZ];         /* the new shell */
114     int get_shell();
115     void check_shell();         /* make sure new shell is valid */
116
117     /* Try each query.  If we ever fail, print error message and exit. */
118
119     status = mr_connect(NULL);
120     if (status) {
121         com_err(whoami, status, " while connecting to Moira");
122         exit(1);
123     }
124
125     status = mr_motd(&motd);
126     if (status) {
127         com_err(whoami, status, " unable to check server status");
128         leave(1);
129     }
130     if (motd) {
131         fprintf(stderr, "The Moira server is currently unavailable:\n%s\n", motd);
132         leave(1);
133     }
134
135     status = mr_auth("chsh");   /* Don't use argv[0] - too easy to fake */
136     if (status) {
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) == NULL)
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, (char *) 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 get_shell(argc, argv, uname)
203   int argc;
204   char **argv;
205   char *uname;                  /* for sanity checking */
206 {
207     /* We'll just take the first information we get since login names 
208        cannot be duplicated in the database. */
209     
210     if (argc < U_END || strcmp(argv[U_NAME], uname))
211     {
212         fprintf(stderr, "Some internal error has occurred.  Try again.\n");
213         leave(3);
214     }
215     
216     printf("Account information last changed on %s\n", argv[U_MODTIME]);
217     printf("by user %s with %s.\n", argv[U_MODBY], argv[U_MODWITH]);
218     printf("Current shell for %s is %s.\n", uname, argv[U_SHELL]); 
219     
220     return(MR_ABORT);           /* Don't pay attention to other matches. */
221 }
222     
223 void check_shell(shell)
224   char *shell;
225 {
226     char *valid_shell;
227     int ok = 0;
228
229     while (valid_shell = getusershell()) {
230         if (strcmp(shell, valid_shell) == 0) {
231             ok = 1;
232             break;
233         }
234         else if (strcmp(shell, 1+strrchr(valid_shell, '/')) == 0) {
235             ok = 1;
236             (void) strcpy(shell, valid_shell);
237             break;
238         }
239     }
240     
241     if (!ok) {
242         if (shell[0] != '/') {
243             fprintf(stderr, "%s it not a standard shell.  ", shell);
244             fprintf(stderr, "You may choose to use a nonstandard\n");
245             fprintf(stderr, "shell, but you must specify its complete ");
246             fprintf(stderr, "path name.\n");
247             leave(2);
248         }
249         else if (access(shell, X_OK)) {
250             fprintf(stderr, "%s is not available.\n", shell);
251             leave(2);
252         }
253         else {
254             printf("%s exists but is an unusual choice.\n", shell);
255             printf("Try again if it is not what you wanted.\n");
256         }
257     }
258 }       
259
260 usage()
261 {
262     fprintf(stderr, "Usage: %s [user]\n", whoami);
263     exit(1);
264 }
265
266 #if defined(ultrix) || defined(_AIX) || defined(sgi)
267 char *getusershell()
268 {
269     static int count = 1;
270
271     switch (count++) {
272     case 1:
273         return("/bin/sh");
274     case 2:
275         return("/bin/csh");
276     case 3:
277         return("/bin/athena/tcsh");
278     case 4:
279         return(NULL);
280     default:
281         count = 1;
282         return(getusershell());
283     }
284 }
285 #endif
This page took 1.607743 seconds and 5 git commands to generate.