Introduction
Introduction Statistics Contact Development Disclaimer Help
passwd.c - ubase - suckless linux base utils
git clone git://git.suckless.org/ubase
Log
Files
Refs
README
LICENSE
---
passwd.c (5780B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <sys/ioctl.h>
3 #include <sys/stat.h>
4 #include <sys/types.h>
5 #include <sys/syscall.h>
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <limits.h>
10 #include <pwd.h>
11 #include <shadow.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17
18 #include "config.h"
19 #include "passwd.h"
20 #include "text.h"
21 #include "util.h"
22
23 static FILE *
24 spw_get_file(const char *user)
25 {
26 FILE *fp = NULL;
27 char file[PATH_MAX];
28 int r;
29
30 r = snprintf(file, sizeof(file), "/etc/tcb/%s/shadow", user);
31 if (r < 0 || (size_t)r >= sizeof(file))
32 eprintf("snprintf:");
33 fp = fopen(file, "r+");
34 if (!fp)
35 fp = fopen("/etc/shadow", "r+");
36 return fp;
37 }
38
39 static int
40 spw_write_file(FILE *fp, const struct spwd *spw, char *pwhash)
41 {
42 struct spwd *spwent;
43 int r = -1, w = 0;
44 FILE *tfp = NULL;
45
46 /* write to temporary file. */
47 tfp = tmpfile();
48 if (!tfp) {
49 weprintf("tmpfile:");
50 goto cleanup;
51 }
52 while ((spwent = fgetspent(fp))) {
53 /* update entry on name match */
54 if (strcmp(spwent->sp_namp, spw->sp_namp) == 0) {
55 spwent->sp_pwdp = pwhash;
56 w++;
57 }
58 errno = 0;
59 if (putspent(spwent, tfp) == -1) {
60 weprintf("putspent:");
61 goto cleanup;
62 }
63 }
64 if (!w) {
65 weprintf("shadow: no matching entry to write to\n");
66 goto cleanup;
67 }
68 fflush(tfp);
69
70 if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -…
71 weprintf("fseek:");
72 goto cleanup;
73 }
74
75 /* write temporary file to (tcb) shadow file */
76 concat(tfp, "tmpfile", fp, "shadow");
77 ftruncate(fileno(fp), ftell(tfp));
78
79 r = 0; /* success */
80 cleanup:
81 if (tfp)
82 fclose(tfp);
83 return r;
84 }
85
86 static int
87 pw_write_file(FILE *fp, const struct passwd *pw, char *pwhash) {
88 struct passwd *pwent;
89 int r = -1, w = 0;
90 FILE *tfp = NULL;
91
92 /* write to temporary file. */
93 tfp = tmpfile();
94 if (!tfp) {
95 weprintf("tmpfile:");
96 goto cleanup;
97 }
98 while ((pwent = fgetpwent(fp))) {
99 /* update entry on name match */
100 if (strcmp(pwent->pw_name, pw->pw_name) == 0) {
101 pwent->pw_passwd = pwhash;
102 w++;
103 }
104 errno = 0;
105 if (putpwent(pwent, tfp) == -1) {
106 weprintf("putpwent:");
107 goto cleanup;
108 }
109 }
110 if (!w) {
111 weprintf("passwd: no matching entry to write to\n");
112 goto cleanup;
113 }
114 fflush(tfp);
115
116 if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -…
117 weprintf("fseek:");
118 goto cleanup;
119 }
120
121 /* write to passwd file. */
122 concat(tfp, "tmpfile", fp, "passwd");
123 ftruncate(fileno(fp), ftell(tfp));
124
125 r = 0; /* success */
126 cleanup:
127 if (tfp)
128 fclose(tfp);
129 return r;
130 }
131
132 /* generates a random base64-encoded salt string of length 16 */
133 static void
134 gensalt(char *s)
135 {
136 static const char b64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXY…
137 uint8_t buf[12];
138 uint32_t n;
139 int i;
140
141 if (syscall(SYS_getrandom, buf, sizeof(buf), 0) < 0)
142 eprintf("getrandom:");
143 for (i = 0; i < 12; i += 3) {
144 n = buf[i] << 16 | buf[i+1] << 8 | buf[i+2];
145 *s++ = b64[n%64]; n /= 64;
146 *s++ = b64[n%64]; n /= 64;
147 *s++ = b64[n%64]; n /= 64;
148 *s++ = b64[n];
149 }
150 *s++ = '\0';
151 }
152
153 static void
154 usage(void)
155 {
156 eprintf("usage: %s [username]\n", argv0);
157 }
158
159 int
160 main(int argc, char *argv[])
161 {
162 char *cryptpass1 = NULL, *cryptpass2 = NULL, *cryptpass3 = NULL;
163 char *inpass, *p, *prevhash = NULL, salt[sizeof(PW_CIPHER) + 16]…
164 struct passwd *pw;
165 struct spwd *spw = NULL;
166 FILE *fp = NULL;
167 int r = -1, status = 1;
168
169 ARGBEGIN {
170 default:
171 usage();
172 } ARGEND;
173
174 pw_init();
175 umask(077);
176
177 errno = 0;
178 if (argc == 0)
179 pw = getpwuid(getuid());
180 else
181 pw = getpwnam(argv[0]);
182 if (!pw) {
183 if (errno)
184 eprintf("getpwnam: %s:", argv[0]);
185 else
186 eprintf("who are you?\n");
187 }
188
189 /* is using shadow entry ? */
190 if (pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') {
191 errno = 0;
192 spw = getspnam(pw->pw_name);
193 if (!spw) {
194 if (errno)
195 eprintf("getspnam: %s:", pw->pw_name);
196 else
197 eprintf("who are you?\n");
198 }
199 }
200
201 /* Flush pending input */
202 ioctl(0, TCFLSH, (void *)0);
203
204 if (getuid() == 0) {
205 goto newpass;
206 } else {
207 if (pw->pw_passwd[0] == '!' ||
208 pw->pw_passwd[0] == '*')
209 eprintf("denied\n");
210 if (pw->pw_passwd[0] == '\0') {
211 goto newpass;
212 }
213 if (pw->pw_passwd[0] == 'x' &&
214 pw->pw_passwd[1] == '\0')
215 prevhash = spw->sp_pwdp;
216 else
217 prevhash = pw->pw_passwd;
218 }
219
220 printf("Changing password for %s\n", pw->pw_name);
221 inpass = getpass("Old password: ");
222 if (!inpass)
223 eprintf("getpass:");
224 if (inpass[0] == '\0')
225 eprintf("no password supplied\n");
226 p = crypt(inpass, prevhash);
227 if (!p)
228 eprintf("crypt:");
229 cryptpass1 = estrdup(p);
230 if (strcmp(cryptpass1, prevhash) != 0)
231 eprintf("incorrect password\n");
232
233 newpass:
234 inpass = getpass("Enter new password: ");
235 if (!inpass)
236 eprintf("getpass:");
237 if (inpass[0] == '\0')
238 eprintf("no password supplied\n");
239
240 if(prevhash) {
241 p = crypt(inpass, prevhash);
242 if (!p)
243 eprintf("crypt:");
244 if (cryptpass1 && strcmp(cryptpass1, p) == 0)
245 eprintf("password left unchanged\n");
246 }
247 gensalt(salt + strlen(salt));
248 p = crypt(inpass, salt);
249 if (!p)
250 eprintf("crypt:");
251 cryptpass2 = estrdup(p);
252
253 /* Flush pending input */
254 ioctl(0, TCFLSH, (void *)0);
255
256 inpass = getpass("Retype new password: ");
257 if (!inpass)
258 eprintf("getpass:");
259 if (inpass[0] == '\0')
260 eprintf("no password supplied\n");
261 p = crypt(inpass, salt);
262 if (!p)
263 eprintf("crypt:");
264 cryptpass3 = estrdup(p);
265 if (strcmp(cryptpass2, cryptpass3) != 0)
266 eprintf("passwords don't match\n");
267
268 fp = spw_get_file(pw->pw_name);
269 if (fp) {
270 r = spw_write_file(fp, spw, cryptpass3);
271 } else {
272 fp = fopen("/etc/passwd", "r+");
273 if (fp)
274 r = pw_write_file(fp, pw, cryptpass3);
275 else
276 weprintf("fopen:");
277 }
278 if (!r)
279 status = 0;
280
281 if (fp)
282 fclose(fp);
283 free(cryptpass3);
284 free(cryptpass2);
285 free(cryptpass1);
286
287 return status;
288 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.