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