]> granicus.if.org Git - shadow/blob - src/vipw.c
Re-indent.
[shadow] / src / vipw.c
1 /*
2   vipw, vigr  edit the password or group file
3   with -s will edit shadow or gshadow file
4  
5   Copyright (C) 1997 Guy Maor <maor@ece.utexas.edu>
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21   */
22
23 #include <config.h>
24
25 #ident "$Id$"
26
27 #include <errno.h>
28 #include <getopt.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <utime.h>
36 #include "defines.h"
37 #include "exitcodes.h"
38 #include "groupio.h"
39 #include "nscd.h"
40 #include "prototypes.h"
41 #include "pwio.h"
42 #include "sgroupio.h"
43 #include "shadowio.h"
44
45 #define MSG_WARN_EDIT_OTHER_FILE _( \
46         "You have modified %s.\n"\
47         "You may need to modify %s for consistency.\n"\
48         "Please use the command `%s' to do so.\n")
49
50 /*
51  * Global variables
52  */
53 static const char *progname, *filename, *fileeditname;
54 static int filelocked = 0, createedit = 0;
55 static int (*unlock) (void);
56 static int quiet = 0;
57
58 /* local function prototypes */
59 static void usage (void);
60 static int create_backup_file (FILE *, const char *, struct stat *);
61 static void vipwexit (const char *, int, int);
62 static void vipwedit (const char *, int (*)(void), int (*)(void));
63
64 /*
65  * usage - display usage message and exit
66  */
67 static void usage (void)
68 {
69         fputs (_("Usage: vipw [options]\n"
70                  "\n"
71                  "Options:\n"
72                  "  -g, --group                   edit group database\n"
73                  "  -h, --help                    display this help message and exit\n"
74                  "  -p, --passwd                  edit passwd database\n"
75                  "  -q, --quiet                   quiet mode\n"
76                  "  -s, --shadow                  edit shadow or gshadow database\n"
77                  "\n"), stderr);
78         exit (E_USAGE);
79 }
80
81 /*
82  *
83  */
84 static int create_backup_file (FILE * fp, const char *backup, struct stat *sb)
85 {
86         struct utimbuf ub;
87         FILE *bkfp;
88         int c;
89         mode_t mask;
90
91         mask = umask (077);
92         bkfp = fopen (backup, "w");
93         umask (mask);
94         if (!bkfp)
95                 return -1;
96
97         c = 0;
98         if (fseeko (fp, 0, SEEK_SET) == 0)
99                 while ((c = getc (fp)) != EOF) {
100                         if (putc (c, bkfp) == EOF)
101                                 break;
102                 }
103         if (c != EOF || ferror (fp) || fflush (bkfp)) {
104                 fclose (bkfp);
105                 unlink (backup);
106                 return -1;
107         }
108         if (fclose (bkfp)) {
109                 unlink (backup);
110                 return -1;
111         }
112
113         ub.actime = sb->st_atime;
114         ub.modtime = sb->st_mtime;
115         if (utime (backup, &ub) ||
116             chmod (backup, sb->st_mode) ||
117             chown (backup, sb->st_uid, sb->st_gid)) {
118                 unlink (backup);
119                 return -1;
120         }
121         return 0;
122 }
123
124 /*
125  *
126  */
127 static void vipwexit (const char *msg, int syserr, int ret)
128 {
129         int err = errno;
130
131         if (createedit)
132                 unlink (fileeditname);
133         if (filelocked)
134                 (*unlock) ();
135         if (msg)
136                 fprintf (stderr, "%s: %s", progname, msg);
137         if (syserr)
138                 fprintf (stderr, ": %s", strerror (err));
139         if (!quiet)
140                 fprintf (stdout, _("\n%s: %s is unchanged\n"), progname,
141                          filename);
142         exit (ret);
143 }
144
145 #ifndef DEFAULT_EDITOR
146 #define DEFAULT_EDITOR "vi"
147 #endif
148
149 /*
150  *
151  */
152 static void
153 vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void))
154 {
155         const char *editor;
156         pid_t pid;
157         struct stat st1, st2;
158         int status;
159         FILE *f;
160         char filebackup[1024], fileedit[1024];
161
162         snprintf (filebackup, sizeof filebackup, "%s-", file);
163         snprintf (fileedit, sizeof fileedit, "%s.edit", file);
164         unlock = file_unlock;
165         filename = file;
166         fileeditname = fileedit;
167
168         if (access (file, F_OK))
169                 vipwexit (file, 1, 1);
170         if (!file_lock ())
171                 vipwexit (_("Couldn't lock file"), errno, 5);
172         filelocked = 1;
173
174         /* edited copy has same owners, perm */
175         if (stat (file, &st1))
176                 vipwexit (file, 1, 1);
177         if (!(f = fopen (file, "r")))
178                 vipwexit (file, 1, 1);
179         if (create_backup_file (f, fileedit, &st1))
180                 vipwexit (_("Couldn't make backup"), errno, 1);
181         createedit = 1;
182
183         editor = getenv ("VISUAL");
184         if (!editor)
185                 editor = getenv ("EDITOR");
186         if (!editor)
187                 editor = DEFAULT_EDITOR;
188
189         if ((pid = fork ()) == -1)
190                 vipwexit ("fork", 1, 1);
191         else if (!pid) {
192                 /* use the system() call to invoke the editor so that it accepts
193                    command line args in the EDITOR and VISUAL environment vars */
194                 char *buf;
195
196                 buf = (char *) malloc (strlen (editor) + strlen (fileedit) + 2);
197                 snprintf (buf, strlen (editor) + strlen (fileedit) + 2,
198                           "%s %s", editor, fileedit);
199                 if (system (buf) != 0) {
200                         fprintf (stderr, "%s: %s: %s\n", progname, editor,
201                                  strerror (errno));
202                         exit (1);
203                 } else
204                         exit (0);
205         }
206
207         for (;;) {
208                 pid = waitpid (pid, &status, WUNTRACED);
209                 if (WIFSTOPPED (status)) {
210                         kill (getpid (), SIGSTOP);
211                         kill (getpid (), SIGCONT);
212                 } else
213                         break;
214         }
215
216         if (pid == -1 || !WIFEXITED (status) || WEXITSTATUS (status))
217                 vipwexit (editor, 1, 1);
218
219         if (stat (fileedit, &st2))
220                 vipwexit (fileedit, 1, 1);
221         if (st1.st_mtime == st2.st_mtime)
222                 vipwexit (0, 0, 0);
223
224         /*
225          * XXX - here we should check fileedit for errors; if there are any,
226          * ask the user what to do (edit again, save changes anyway, or quit
227          * without saving). Use pwck or grpck to do the check.  --marekm
228          */
229         createedit = 0;
230         unlink (filebackup);
231         link (file, filebackup);
232         if (rename (fileedit, file) == -1) {
233                 fprintf (stderr,
234                          _
235                          ("%s: can't restore %s: %s (your changes are in %s)\n"),
236                          progname, file, strerror (errno), fileedit);
237                 vipwexit (0, 0, 1);
238         }
239
240         (*file_unlock) ();
241 }
242
243 int main (int argc, char **argv)
244 {
245         int editshadow = 0;
246         char *a;
247         int do_vipw;
248
249         setlocale (LC_ALL, "");
250         bindtextdomain (PACKAGE, LOCALEDIR);
251         textdomain (PACKAGE);
252
253         progname = ((a = strrchr (*argv, '/')) ? a + 1 : *argv);
254         do_vipw = (strcmp (progname, "vigr") != 0);
255
256         {
257                 /*
258                  * Parse the command line options.
259                  */
260                 int c;
261                 static struct option long_options[] = {
262                         {"group", no_argument, NULL, 'g'},
263                         {"help", no_argument, NULL, 'h'},
264                         {"passwd", no_argument, NULL, 'p'},
265                         {"quiet", no_argument, NULL, 'q'},
266                         {"shadow", no_argument, NULL, 's'},
267                 };
268                 while ((c =
269                         getopt_long (argc, argv, "ghpqs",
270                                      long_options, NULL)) != -1) {
271                         switch (c) {
272                         case 'g':
273                                 do_vipw = 0;
274                                 break;
275                         case 'h':
276                                 usage ();
277                                 break;
278                         case 'p':
279                                 do_vipw = 1;
280                                 break;
281                         case 'q':
282                                 quiet = 1;
283                                 break;
284                         case 's':
285                                 editshadow = 1;
286                                 break;
287                         default:
288                                 usage ();
289                         }
290                 }
291         }
292
293         if (do_vipw) {
294                 if (editshadow) {
295                         vipwedit (SHADOW_FILE, spw_lock, spw_unlock);
296                         printf (MSG_WARN_EDIT_OTHER_FILE,
297                                 SHADOW_FILE,
298                                 PASSWD_FILE,
299                                 "vipw");
300                 } else {
301                         vipwedit (PASSWD_FILE, pw_lock, pw_unlock);
302                         if (spw_file_present ()) {
303                                 printf (MSG_WARN_EDIT_OTHER_FILE,
304                                         PASSWD_FILE,
305                                         SHADOW_FILE,
306                                         "vipw -s");
307                         }
308                 }
309         } else {
310 #ifdef SHADOWGRP
311                 if (editshadow) {
312                         vipwedit (SGROUP_FILE, sgr_lock, sgr_unlock);
313                         printf (MSG_WARN_EDIT_OTHER_FILE,
314                                 SGROUP_FILE,
315                                 GROUP_FILE,
316                                 "vigr");
317                 } else {
318 #endif
319                         vipwedit (GROUP_FILE, gr_lock, gr_unlock);
320 #ifdef SHADOWGRP
321                         if (sgr_file_present ()) {
322                                 printf (MSG_WARN_EDIT_OTHER_FILE,
323                                         GROUP_FILE,
324                                         SGROUP_FILE,
325                                         "vigr -s");
326                         }
327                 }
328 #endif
329         }
330
331         nscd_flush_cache ("passwd");
332         nscd_flush_cache ("group");
333
334         exit (E_SUCCESS);
335 }