]> andersk Git - moira.git/blob - clients/chsh/chsh.c
moved from clients/passwd to clients/chsh
[moira.git] / clients / chsh / 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 #include <mrclient.h>
22
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 RCSID("$Header$");
28
29 void usage(void);
30 int chsh(char *uname);
31 int get_shell(int argc, char **argv, void *uname);
32 int get_fmodtime(int argc, char **argv, void *uname);
33 void check_shell(char *shell);
34 #ifndef HAVE_GETUSERSHELL
35 char *getusershell(void);
36 #endif
37
38 char *whoami;
39
40 int main(int argc, char *argv[])
41 {
42   char *uname;
43
44   if ((whoami = strrchr(argv[0], '/')) == NULL)
45     whoami = argv[0];
46   else
47     whoami++;
48
49   if (argc > 2)
50     usage();
51
52   if (argc == 2)
53     uname = argv[1];
54   else
55     {
56       uname = mrcl_krb_user();
57       if (!uname)
58         exit(1);
59     }
60
61   exit(chsh(uname));
62 }
63
64 int chsh(char *uname)
65 {
66   int status;                   /* general purpose exit status */
67   int q_argc;                   /* argc for mr_query */
68   char *q_argv[U_END];          /* argv for mr_query */
69   char *motd;                   /* determine Moira server status */
70
71   int got_one = 0;              /* have we got a new shell yet? */
72   char shell[BUFSIZ];           /* the new shell */
73
74   if (mrcl_connect(NULL, "chsh", 2, 1) != MRCL_SUCCESS)
75     exit(1);
76
77   /* First, do an access check */
78
79   q_argv[USH_NAME] = uname;
80   q_argv[USH_SHELL] = "junk";
81   q_argc = USH_END;
82
83   if ((status = mr_access("update_user_shell", q_argc, q_argv)))
84     {
85       com_err(whoami, status, "; shell not\nchanged.");
86       exit(2);
87     }
88
89   printf("Changing login shell for %s.\n", uname);
90
91   /* Display current information */
92
93   q_argv[NAME] = uname;
94   q_argc = NAME + 1;
95
96   if ((status = mr_query("get_finger_by_login", q_argc, q_argv,
97                          get_fmodtime, uname)))
98     {
99       com_err(whoami, status, "while getting user information.");
100       exit(2);
101     }
102
103   if ((status = mr_query("get_user_account_by_login", q_argc, q_argv,
104                          get_shell, uname)))
105     {
106       com_err(whoami, status, "while getting user information.");
107       exit(2);
108     }
109
110   /* Ask for new shell */
111   while (!got_one)
112     {
113       printf("New shell: ");
114       if (!fgets(shell, sizeof(shell), stdin))
115         exit(0);
116       got_one = (strlen(shell) > 1);
117     }
118
119   shell[strlen(shell) - 1] = 0; /* strip off newline */
120
121   /* Make sure we have a valid shell.  This routine could exit */
122   check_shell(shell);
123
124   /* Change shell */
125
126   printf("Changing shell to %s...\n", shell);
127
128   q_argv[USH_NAME] = uname;
129   q_argv[USH_SHELL] = shell;
130   q_argc = USH_END;
131   if ((status = mr_query("update_user_shell", q_argc, q_argv, NULL, NULL)))
132     {
133       com_err(whoami, status, "while changing shell.");
134       exit(2);
135     }
136
137   printf("Shell successfully changed.\n");
138   mr_disconnect();
139
140   return 0;
141 }
142
143 int get_shell(int argc, char **argv, void *uname)
144 {
145   /* We'll just take the first information we get since login names
146      cannot be duplicated in the database. */
147
148   if (argc < U_END || strcmp(argv[U_NAME], uname))
149     {
150       fprintf(stderr, "Some internal error has occurred.  Try again.\n");
151       exit(3);
152     }
153
154   printf("Current shell for %s is %s.\n", (char *)uname, argv[U_SHELL]);
155
156   return MR_ABORT;              /* Don't pay attention to other matches. */
157 }
158
159 int get_fmodtime(int argc, char **argv, void *uname)
160 {
161   /* We'll just take the first information we get since login names
162      cannot be duplicated in the database. */
163
164   if (argc < F_END || strcmp(argv[F_NAME], uname))
165     {
166       fprintf(stderr, "Some internal error has occurred.  Try again.\n");
167       exit(3);
168     }
169
170   printf("Finger information last changed on %s\n", argv[F_MODTIME]);
171   printf("by user %s with %s.\n", argv[F_MODBY], argv[F_MODWITH]);
172
173   return MR_ABORT;              /* Don't pay attention to other matches. */
174 }
175
176 void check_shell(char *shell)
177 {
178   char *valid_shell;
179   int ok = 0;
180
181   while ((valid_shell = getusershell()))
182     {
183       if (!strcmp(shell, valid_shell))
184         {
185           ok = 1;
186           break;
187         }
188       else if (!strcmp(shell, 1 + strrchr(valid_shell, '/')))
189         {
190           ok = 1;
191           strcpy(shell, valid_shell);
192           break;
193         }
194     }
195
196   if (!ok)
197     {
198       if (shell[0] != '/')
199         {
200           fprintf(stderr, "%s is not a standard shell.  ", shell);
201           fprintf(stderr, "You may choose to use a nonstandard\n");
202           fprintf(stderr, "shell, but you must specify its complete ");
203           fprintf(stderr, "path name.\n");
204           exit(2);
205         }
206       else if (access(shell, X_OK))
207         {
208           fprintf(stderr, "%s is not available.\n", shell);
209           exit(2);
210         }
211       else
212         {
213           printf("%s exists but is an unusual choice.\n", shell);
214           printf("Try again if it is not what you wanted.\n");
215         }
216     }
217 }
218
219 void usage(void)
220 {
221   fprintf(stderr, "Usage: %s [user]\n", whoami);
222   exit(1);
223 }
224
225 #ifndef HAVE_GETUSERSHELL
226 #include <sys/param.h>
227
228 char *getusershell(void)
229 {
230   static FILE *shells = NULL;
231
232   /* In a sane universe, no shell will have a length longer than
233    * MAXPATHLEN. If any line in /etc/shells does, we'll lose, but
234    * not much. shrug.
235    */
236   static char buf[MAXPATHLEN];
237   char *p;
238
239   if (!shells)
240     {
241       shells = fopen("/etc/shells", "r");
242       if (!shells)
243         {
244           fprintf(stderr, "%s: Can't open /etc/shells. Unable to determine if "
245                   "this is a normal shell.\n\n", whoami);
246           return NULL;
247         }
248     }
249
250   while (1)
251     {
252       if (!fgets(buf, sizeof(buf), shells))
253         {
254           fclose(shells);
255           shells = NULL;
256           return NULL;
257         }
258
259       if (buf[0] != '/')
260         continue;
261
262       p = strchr(buf, '\n');
263       if (p)
264         *p = '\0';
265
266       return buf;
267     }
268 }
269 #endif
This page took 0.084932 seconds and 5 git commands to generate.