]> granicus.if.org Git - shadow/blob - src/vipw.c
[svn-upgrade] Integrating new upstream version, shadow (4.0.5)
[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 #include "rcsid.h"
26 RCSID (PKG_VER "$Id: vipw.c,v 1.7 2004/06/03 00:27:19 kloczek Exp $")
27 #include "defines.h"
28 #include <errno.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <sys/types.h>
34 #include <signal.h>
35 #include <utime.h>
36 #include "prototypes.h"
37 #include "pwio.h"
38 #include "shadowio.h"
39 #include "groupio.h"
40 #include "sgroupio.h"
41 #include "nscd.h"
42 static const char *progname, *filename, *fileeditname;
43 static int filelocked = 0, createedit = 0;
44 static int (*unlock) (void);
45
46 /* local function prototypes */
47 static int create_backup_file (FILE *, const char *, struct stat *);
48 static void vipwexit (const char *, int, int);
49 static void vipwedit (const char *, int (*)(void), int (*)(void));
50
51 static int
52 create_backup_file (FILE * fp, const char *backup, struct stat *sb)
53 {
54         struct utimbuf ub;
55         FILE *bkfp;
56         int c;
57         mode_t mask;
58
59         mask = umask (077);
60         bkfp = fopen (backup, "w");
61         umask (mask);
62         if (!bkfp)
63                 return -1;
64
65         c = 0;
66         if (fseek(fp, 0, SEEK_SET) == 0)
67                 while ((c = getc(fp)) != EOF) {
68                         if (putc(c, bkfp) == EOF)
69                                 break;
70                 }
71         if (c != EOF || ferror(fp) || fflush(bkfp)) {
72                 fclose (bkfp);
73                 unlink (backup);
74                 return -1;
75         }
76         if (fclose (bkfp)) {
77                 unlink (backup);
78                 return -1;
79         }
80
81         ub.actime = sb->st_atime;
82         ub.modtime = sb->st_mtime;
83         if (utime (backup, &ub) ||
84             chmod (backup, sb->st_mode) ||
85             chown (backup, sb->st_uid, sb->st_gid)) {
86                 unlink (backup);
87                 return -1;
88         }
89         return 0;
90 }
91
92
93 static void vipwexit (const char *msg, int syserr, int ret)
94 {
95         int err = errno;
96
97         if (filelocked)
98                 (*unlock) ();
99         if (createedit)
100                 unlink (fileeditname);
101         if (msg)
102                 fprintf (stderr, "%s: %s", progname, msg);
103         if (syserr)
104                 fprintf (stderr, ": %s", strerror (err));
105         fprintf (stderr, _("\n%s: %s is unchanged\n"), progname, filename);
106         exit (ret);
107 }
108
109 #ifndef DEFAULT_EDITOR
110 #define DEFAULT_EDITOR "vi"
111 #endif
112
113 static void
114 vipwedit (const char *file, int (*file_lock) (void),
115           int (*file_unlock) (void))
116 {
117         const char *editor;
118         pid_t pid;
119         struct stat st1, st2;
120         int status;
121         FILE *f;
122         char filebackup[1024], fileedit[1024];
123
124         snprintf (filebackup, sizeof filebackup, "%s-", file);
125         snprintf (fileedit, sizeof fileedit, "%s.edit", file);
126         unlock = file_unlock;
127         filename = file;
128         fileeditname = fileedit;
129
130         if (access (file, F_OK))
131                 vipwexit (file, 1, 1);
132         if (!file_lock ())
133                 vipwexit (_("Couldn't lock file"), errno, 5);
134         filelocked = 1;
135
136         /* edited copy has same owners, perm */
137         if (stat (file, &st1))
138                 vipwexit (file, 1, 1);
139         if (!(f = fopen (file, "r")))
140                 vipwexit (file, 1, 1);
141         if (create_backup_file (f, fileedit, &st1))
142                 vipwexit (_("Couldn't make backup"), errno, 1);
143         createedit = 1;
144
145         editor = getenv ("VISUAL");
146         if (!editor)
147                 editor = getenv ("EDITOR");
148         if (!editor)
149                 editor = DEFAULT_EDITOR;
150
151         if ((pid = fork ()) == -1)
152                 vipwexit ("fork", 1, 1);
153         else if (!pid) {
154                 /* use the system() call to invoke the editor so that it accepts
155                    command line args in the EDITOR and VISUAL environment vars */
156                 char *buf;
157
158                 buf =
159                     (char *) malloc (strlen (editor) + strlen (fileedit) +
160                                      2);
161                 snprintf (buf, strlen (editor) + strlen (fileedit) + 2,
162                           "%s %s", editor, fileedit);
163                 if (system (buf) != 0) {
164                         fprintf (stderr, "%s: %s: %s\n", progname, editor,
165                                  strerror (errno));
166                         exit (1);
167                 } else
168                         exit (0);
169         }
170
171         for (;;) {
172                 pid = waitpid (pid, &status, WUNTRACED);
173                 if (WIFSTOPPED (status)) {
174                         kill (getpid (), SIGSTOP);
175                         kill (getpid (), SIGCONT);
176                 } else
177                         break;
178         }
179
180         if (pid == -1 || !WIFEXITED (status) || WEXITSTATUS (status))
181                 vipwexit (editor, 1, 1);
182
183         if (stat (fileedit, &st2))
184                 vipwexit (fileedit, 1, 1);
185         if (st1.st_mtime == st2.st_mtime)
186                 vipwexit (0, 0, 0);
187
188         /*
189          * XXX - here we should check fileedit for errors; if there are any,
190          * ask the user what to do (edit again, save changes anyway, or quit
191          * without saving). Use pwck or grpck to do the check.  --marekm
192          */
193
194         createedit = 0;
195         unlink (filebackup);
196         link (file, filebackup);
197         if (rename (fileedit, file) == -1) {
198                 fprintf (stderr,
199                          _
200                          ("%s: can't restore %s: %s (your changes are in %s)\n"),
201                          progname, file, strerror (errno), fileedit);
202                 vipwexit (0, 0, 1);
203         }
204
205         (*file_unlock) ();
206 }
207
208
209 int main (int argc, char **argv)
210 {
211         int flag;
212         int editshadow = 0;
213         char *c;
214         int e = 1;
215         int do_vipw;
216
217         setlocale (LC_ALL, "");
218         bindtextdomain (PACKAGE, LOCALEDIR);
219         textdomain (PACKAGE);
220
221         progname = ((c = strrchr (*argv, '/')) ? c + 1 : *argv);
222         do_vipw = (strcmp (progname, "vigr") != 0);
223
224         while ((flag = getopt (argc, argv, "ghps")) != EOF) {
225                 switch (flag) {
226                 case 'p':
227                         do_vipw = 1;
228                         break;
229                 case 'g':
230                         do_vipw = 0;
231                         break;
232                 case 's':
233                         editshadow = 1;
234                         break;
235                 case 'h':
236                         e = 0;
237                 default:
238                         printf (_("Usage:\n\
239 `vipw' edits /etc/passwd        `vipw -s' edits /etc/shadow\n\
240 `vigr' edits /etc/group         `vigr -s' edits /etc/gshadow\n\
241 "));
242                         exit (e);
243                 }
244         }
245
246         if (do_vipw) {
247 #ifdef SHADOWPWD
248                 if (editshadow)
249                         vipwedit (SHADOW_FILE, spw_lock, spw_unlock);
250                 else
251 #endif
252                         vipwedit (PASSWD_FILE, pw_lock, pw_unlock);
253         } else {
254 #ifdef SHADOWGRP
255                 if (editshadow)
256                         vipwedit (SGROUP_FILE, sgr_lock, sgr_unlock);
257                 else
258 #endif
259                         vipwedit (GROUP_FILE, gr_lock, gr_unlock);
260         }
261
262         nscd_flush_cache ("passwd");
263         nscd_flush_cache ("group");
264 #ifdef SHADOWPWD
265         nscd_flush_cache ("shadow");
266 #endif
267         return 0;
268 }