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