Upload Tizen:Base source
[framework/base/util-linux-ng.git] / login-utils / setpwnam.c
1 /*
2  *  setpwnam.c --
3  *  edit an entry in a password database.
4  *
5  *  (c) 1994 Salvatore Valente <svalente@mit.edu>
6  *  This file is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public License as
8  *  published by the Free Software Foundation; either version 2 of the
9  *  License, or (at your option) any later version.
10  *
11  *  Edited 11/10/96 (DD/MM/YY ;-) by Nicolai Langfeldt (janl@math.uio.no)
12  *  to read /etc/passwd directly so that passwd, chsh and chfn can work
13  *  on machines that run NIS (nĂ© YP).  Changes will not be made to
14  *  usernames starting with +.
15  *  
16  *  This file is distributed with no warranty.
17  *
18  *  Usage:
19  *  1) get a struct passwd * from getpwnam().
20  *     You should assume a struct passwd has an infinite number of fields,
21  *     so you should not try to create one from scratch.
22  *  2) edit the fields you want to edit.
23  *  3) call setpwnam() with the edited struct passwd.
24  *
25  *  A _normal user_ program should never directly manipulate
26  *  /etc/passwd but use getpwnam() and (family, as well as)
27  *  setpwnam().
28  *
29  *  But, setpwnam was made to _edit_ the password file.  For use by
30  *  chfn, chsh and passwd.  _I_ _HAVE_ to read and write /etc/passwd
31  *  directly.  Let those who say nay be forever silent and think about
32  *  how getpwnam (and family) works on a machine running YP.
33  *
34  *  Added checks for failure of malloc() and removed error reporting
35  *  to stderr, this is a library function and should not print on the
36  *  screen, but return appropriate error codes.
37  *  27-Jan-97  - poe@daimi.aau.dk
38  *
39  *  Thanks to "two guys named Ian".
40  *
41  *   $Author: poer $
42  *   $Revision: 1.13 $
43  *   $Date: 1997/06/23 08:26:29 $
44  *
45  */
46
47 #undef DEBUG
48
49 /*  because I use getpwent(), putpwent(), etc... */
50 #define _SVID_SOURCE
51
52 #include <sys/types.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <unistd.h>
57 #include <fcntl.h>
58 #include <pwd.h>
59 #include <errno.h>
60 #include <signal.h>
61 #include <sys/resource.h>
62 #include <sys/stat.h>
63 #include <paths.h>
64
65 #include "setpwnam.h"
66
67 #define false 0
68 #define true 1
69
70 typedef int boolean;
71
72 static void pw_init(void);
73
74 /*
75  *  setpwnam () --
76  *      takes a struct passwd in which every field is filled in and valid.
77  *      If the given username exists in the passwd file, the entry is
78  *      replaced with the given entry.
79  */
80 int 
81 setpwnam (struct passwd *pwd)
82 {
83     FILE *fp = NULL, *pwf = NULL;
84     int x, save_errno, fd, ret;
85     boolean found;
86     int oldumask;
87     int namelen;
88     int buflen = 256;
89     int contlen;
90     char *linebuf = malloc(buflen);
91
92     if (!linebuf) return -1;
93
94     oldumask = umask(0);   /* Create with exact permissions */
95
96     pw_init();
97
98     /* sanity check */
99     for (x = 0; x < 3; x++) {
100         if (x > 0) sleep(1);
101         fd = open(PTMPTMP_FILE, O_WRONLY|O_CREAT|O_EXCL, 0644);
102         if (fd == -1) {
103             umask(oldumask);
104             return -1;
105         }
106         ret = link(PTMPTMP_FILE, PTMP_FILE);
107         unlink(PTMPTMP_FILE);
108         if (ret == -1)
109             close(fd);
110         else
111             break;
112     }
113     umask(oldumask);
114     if (ret == -1) return -1;
115
116     /* ptmp should be owned by root.root or root.wheel */
117     if (chown(PTMP_FILE, (uid_t) 0, (gid_t) 0) < 0) return -1;
118
119     /* open ptmp for writing and passwd for reading */
120     fp = fdopen(fd, "w");
121     if (!fp) goto fail;
122
123     pwf = fopen(PASSWD_FILE, "r");
124     if (!pwf) goto fail;
125
126     namelen = strlen(pwd->pw_name);
127
128     /* parse the passwd file */
129     found = false;
130     /* Do you wonder why I don't use getpwent? Read comments at top of file */
131     while (fgets(linebuf, buflen, pwf) != NULL) {
132         contlen = strlen(linebuf);
133         while (linebuf[contlen-1] != '\n' && !feof(pwf)) {
134             /* Extend input buffer if it failed getting the whole line */
135
136             /* So now we double the buffer size */
137             buflen *= 2;
138
139             linebuf = realloc(linebuf, buflen);
140             if (linebuf == NULL) goto fail;
141
142             /* And fill the rest of the buffer */
143             if (fgets(&linebuf[contlen], buflen/2, pwf) == NULL) break;
144             contlen = strlen(linebuf);
145       
146             /* That was a lot of work for nothing.  Gimme perl! */
147         }
148
149         /* Is this the username we were sent to change? */
150         if (!found && linebuf[namelen] == ':' &&
151             !strncmp(linebuf, pwd->pw_name, namelen)) {
152             /* Yes! So go forth in the name of the Lord and change it! */
153             if (putpwent(pwd, fp) < 0) goto fail;
154             found = true;
155             continue;
156         }
157         /* Nothing in particular happened, copy input to output */
158         fputs(linebuf, fp);
159     }
160
161     if (fclose(fp) < 0) goto fail;
162     fp = NULL;
163     close (fd);
164     fd = -1;
165     fclose (pwf); /* I don't think I want to know if this failed */
166     pwf = NULL;
167
168     if (!found) {
169         errno = ENOENT; /* give me something better */
170         goto fail;
171     }
172
173     /* we don't care if we can't remove the backup file */
174     unlink(PASSWD_FILE".OLD");
175     /* we don't care if we can't create the backup file */
176     link(PASSWD_FILE, PASSWD_FILE".OLD");
177     /* we DO care if we can't rename to the passwd file */
178     if(rename(PTMP_FILE, PASSWD_FILE) < 0)
179         goto fail;
180     /* finally:  success */
181     return 0;
182
183 fail:
184     save_errno = errno;
185     if (fp != NULL) fclose (fp);
186     if (pwf != NULL) fclose(pwf);
187     if (fd >= 0) close (fd);
188     free(linebuf);
189     unlink(PTMP_FILE);
190     errno = save_errno;
191     return -1;
192 }
193
194 /* Set up the limits so that we're not foiled */
195
196 static void 
197 pw_init()
198 {
199     struct rlimit rlim;
200
201     /* Unlimited resource limits. */
202     rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
203     setrlimit(RLIMIT_CPU, &rlim);
204     setrlimit(RLIMIT_FSIZE, &rlim);
205     setrlimit(RLIMIT_STACK, &rlim);
206     setrlimit(RLIMIT_DATA, &rlim);
207     setrlimit(RLIMIT_RSS, &rlim);
208
209 #ifndef DEBUG
210     /* Don't drop core (not really necessary, but GP's). */
211     rlim.rlim_cur = rlim.rlim_max = 0;
212     setrlimit(RLIMIT_CORE, &rlim);
213 #endif
214
215     /* Turn off signals. */
216     signal(SIGALRM, SIG_IGN);
217     signal(SIGHUP, SIG_IGN);
218     signal(SIGINT, SIG_IGN);
219     signal(SIGPIPE, SIG_IGN);
220     signal(SIGQUIT, SIG_IGN);
221     signal(SIGTERM, SIG_IGN);
222     signal(SIGTSTP, SIG_IGN);
223     signal(SIGTTOU, SIG_IGN);
224
225     /* Create with exact permissions. */
226     umask(0);
227 }