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