aboutsummaryrefslogtreecommitdiff
path: root/loginutils/passwd.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-11-30 16:41:15 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-11-30 16:41:15 +0000
commitab24e18c7a32ee1637be19f239e9dd9d7c7f6534 (patch)
tree2646cfd66b5a8d279ad360aaa989a814eeecfd64 /loginutils/passwd.c
parentb8bb27c7ea37c9885b1ded36d0f7807a09ede712 (diff)
downloadbusybox-w32-ab24e18c7a32ee1637be19f239e9dd9d7c7f6534.tar.gz
busybox-w32-ab24e18c7a32ee1637be19f239e9dd9d7c7f6534.tar.bz2
busybox-w32-ab24e18c7a32ee1637be19f239e9dd9d7c7f6534.zip
passwd: rework:
* do not make backup copy by copying (just retain old file) * correctly fall back to /etc/passwd if user is not in shadow * fix bug with overlong passwd entries * be permissive on some kinds of failures * reduce stack usage * code size: -500 bytes
Diffstat (limited to 'loginutils/passwd.c')
-rw-r--r--loginutils/passwd.c532
1 files changed, 249 insertions, 283 deletions
diff --git a/loginutils/passwd.c b/loginutils/passwd.c
index 2811ab72e..41033e51a 100644
--- a/loginutils/passwd.c
+++ b/loginutils/passwd.c
@@ -6,122 +6,234 @@
6#include "busybox.h" 6#include "busybox.h"
7#include <syslog.h> 7#include <syslog.h>
8 8
9static char crypt_passwd[128];
10 9
11static int create_backup(const char *backup, FILE * fp); 10static void nuke_str(char *str)
12static int new_password(const struct passwd *pw, int amroot, int algo); 11{
13static void set_filesize_limit(int blocks); 12 if (str) memset(str, 0, strlen(str));
13}
14 14
15 15
16static int get_algo(char *a) 16static int i64c(int i)
17{ 17{
18 int x = 1; /* standard: MD5 */ 18 if (i <= 0)
19 return '.';
20 if (i == 1)
21 return '/';
22 if (i >= 2 && i < 12)
23 return ('0' - 2 + i);
24 if (i >= 12 && i < 38)
25 return ('A' - 12 + i);
26 if (i >= 38 && i < 63)
27 return ('a' - 38 + i);
28 return 'z';
29}
30
19 31
32static char *crypt_make_salt(void)
33{
34 time_t now;
35 static unsigned long x;
36 static char result[3];
37
38 time(&now);
39 x += now + getpid() + clock();
40 result[0] = i64c(((x >> 18) ^ (x >> 6)) & 077);
41 result[1] = i64c(((x >> 12) ^ x) & 077);
42 result[2] = '\0';
43 return result;
44}
45
46
47static char* new_password(const struct passwd *pw, const char *old_crypted,
48 uid_t myuid, int algo)
49{
50 char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */
51 char *orig = "";
52 char *newp = NULL;
53 char *cipher = NULL;
54 char *cp = NULL;
55 char *ret = NULL; /* failure so far */
56
57 if (myuid && old_crypted[0]) {
58 orig = bb_askpass(0, "Old password:"); /* returns ptr to static */
59 if (!orig)
60 goto err_ret;
61 cipher = pw_encrypt(orig, old_crypted); /* returns ptr to static */
62 if (strcmp(cipher, old_crypted) != 0) {
63 syslog(LOG_WARNING, "incorrect password for '%s'",
64 pw->pw_name);
65 bb_do_delay(FAIL_DELAY);
66 puts("Incorrect password");
67 goto err_ret;
68 }
69 }
70 orig = xstrdup(orig); /* or else bb_askpass() will destroy it */
71 newp = bb_askpass(0, "Enter the new password (minimum of 5 characters).\n"
72 "Please use a combination of upper and lower case letters and numbers.\n"
73 "Enter new password:"); /* returns ptr to static */
74 if (!newp)
75 goto err_ret;
76 newp = xstrdup(newp); /* we are going to bb_askpass() again, so save it */
77 if (obscure(orig, newp, pw)) {
78 if (myuid)
79 goto err_ret; /* non-root is not allowed to have weak passwd */
80 puts("\nWarning: weak password (continuing)");
81 }
82
83 cp = bb_askpass(0, "Re-enter new password:");
84 if (!cp)
85 goto err_ret;
86 if (strcmp(cp, newp)) {
87 puts("Passwords do not match");
88 goto err_ret;
89 }
90
91 memset(salt, 0, sizeof(salt));
92 if (algo == 1) { /* MD5 */
93 strcpy(salt, "$1$");
94 strcat(salt, crypt_make_salt());
95 strcat(salt, crypt_make_salt());
96 strcat(salt, crypt_make_salt());
97 }
98 strcat(salt, crypt_make_salt());
99 ret = xstrdup(pw_encrypt(newp, salt)); /* returns ptr to static */
100 /* whee, success! */
101
102 err_ret:
103 nuke_str(orig);
104 if (ENABLE_FEATURE_CLEAN_UP) free(orig);
105 nuke_str(newp);
106 if (ENABLE_FEATURE_CLEAN_UP) free(newp);
107 nuke_str(cipher);
108 nuke_str(cp);
109 return ret;
110}
111
112
113static void set_filesize_limit(int blocks)
114{
115 struct rlimit rlimit_fsize;
116
117 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;
118 setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
119}
120
121
122#if 0
123static int get_algo(char *a)
124{
125 /* standard: MD5 */
126 int x = 1;
20 if (strcasecmp(a, "des") == 0) 127 if (strcasecmp(a, "des") == 0)
21 x = 0; 128 x = 0;
22 return x; 129 return x;
23} 130}
131#endif
24 132
25 133
26static int update_passwd(const struct passwd *pw, const char *crypt_pw) 134static int update_passwd(const char *filename, const char *username,
135 const char *new_pw)
27{ 136{
28 char filename[1024];
29 char buf[1025];
30 char buffer[80];
31 char username[32];
32 char *pw_rest;
33 int mask;
34 int continued;
35 FILE *fp;
36 FILE *out_fp;
37 struct stat sb; 137 struct stat sb;
38 struct flock lock; 138 struct flock lock;
39 139 FILE *old_fp;
40#if ENABLE_FEATURE_SHADOWPASSWDS 140 FILE *new_fp;
41 if (access(bb_path_shadow_file, F_OK) == 0) { 141 char *new_name;
42 snprintf(filename, sizeof filename, "%s", bb_path_shadow_file); 142 char *last_char;
43 } else 143 unsigned user_len;
44#endif 144 int old_fd;
45 { 145 int new_fd;
46 snprintf(filename, sizeof filename, "%s", bb_path_passwd_file); 146 int i;
147 int ret = 1; /* failure */
148
149 /* New passwd file, "/etc/passwd+" for now */
150 new_name = xasprintf("%s+", filename);
151 last_char = &new_name[strlen(new_name)-1];
152 username = xasprintf("%s:", username);
153 user_len = strlen(username);
154
155 old_fp = fopen(filename, "r+");
156 if (!old_fp)
157 goto free_mem;
158 old_fd = fileno(old_fp);
159
160 /* Try to create "/etc/passwd+". Wait if it exists. */
161 i = 30;
162 do {
163 // FIXME: on last iteration try w/o O_EXCL but with O_TRUNC?
164 new_fd = open(new_name, O_WRONLY|O_CREAT|O_EXCL,0600);
165 if (new_fd >= 0) goto created;
166 if (errno != EEXIST) break;
167 usleep(100000); /* 0.1 sec */
168 } while (--i);
169 bb_perror_msg("cannot create '%s'", new_name);
170 goto close_old_fp;
171 created:
172 if (!fstat(old_fd, &sb)) {
173 fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */
174 fchown(new_fd, sb.st_uid, sb.st_gid);
47 } 175 }
48 176 new_fp = fdopen(new_fd, "w");
49 fp = fopen(filename, "r+"); 177 if (!new_fp) {
50 if (fp == 0 || fstat(fileno(fp), &sb)) { 178 close(new_fd);
51 /* return 0; */ 179 goto unlink_new;
52 return 1;
53 } 180 }
54 181
182 /* Backup file is "/etc/passwd-" */
183 last_char[0] = '-';
184 /* Delete old one, create new as a hardlink to current */
185 i = (unlink(new_name) && errno != ENOENT);
186 if (i || link(filename, new_name))
187 bb_perror_msg("warning: cannot create backup copy '%s'", new_name);
188 last_char[0] = '+';
189
55 /* Lock the password file before updating */ 190 /* Lock the password file before updating */
56 lock.l_type = F_WRLCK; 191 lock.l_type = F_WRLCK;
57 lock.l_whence = SEEK_SET; 192 lock.l_whence = SEEK_SET;
58 lock.l_start = 0; 193 lock.l_start = 0;
59 lock.l_len = 0; 194 lock.l_len = 0;
60 if (fcntl(fileno(fp), F_SETLK, &lock) < 0) { 195 if (fcntl(old_fd, F_SETLK, &lock) < 0)
61 bb_perror_msg("%s", filename); 196 bb_perror_msg("warning: cannot lock '%s'", filename);
62 return 1;
63 }
64 lock.l_type = F_UNLCK; 197 lock.l_type = F_UNLCK;
65 198
66 snprintf(buf, sizeof buf, "%s-", filename); 199 /* Read current password file, write updated one */
67 if (create_backup(buf, fp)) { 200 while (1) {
68 fcntl(fileno(fp), F_SETLK, &lock); 201 char *line = xmalloc_fgets(old_fp);
69 fclose(fp); 202 if (!line) break; /* EOF/error */
70 return 1; 203 if (strncmp(username, line, user_len) == 0) {
204 /* we have a match with "username:"... */
205 const char *cp = line + user_len;
206 /* now cp -> old passwd, skip it: */
207 cp = strchr(cp, ':');
208 if (!cp) cp = "";
209 /* now cp -> ':' after old passwd or -> "" */
210 fprintf(new_fp, "%s%s%s", username, new_pw, cp);
211 /* Erase password in memory */
212 } else
213 fputs(line, new_fp);
214 free(line);
71 } 215 }
72 snprintf(buf, sizeof buf, "%s+", filename); 216 fcntl(old_fd, F_SETLK, &lock);
73 mask = umask(0777); 217
74 out_fp = fopen(buf, "w"); 218 /* We do want all of them to execute, thus | instead of || */
75 umask(mask); 219 if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp))
76 if ((!out_fp) || (fchmod(fileno(out_fp), sb.st_mode & 0777)) 220 || rename(new_name, filename)
77 || (fchown(fileno(out_fp), sb.st_uid, sb.st_gid))) { 221 ) {
78 fcntl(fileno(fp), F_SETLK, &lock); 222 /* At least one of those failed */
79 fclose(fp); 223 goto unlink_new;
80 fclose(out_fp);
81 return 1;
82 } 224 }
225 ret = 0; /* whee, success! */
83 226
84 continued = 0; 227 unlink_new:
85 snprintf(username, sizeof username, "%s:", pw->pw_name); 228 if (ret) unlink(new_name);
86 rewind(fp);
87 while (!feof(fp)) {
88 fgets(buffer, sizeof buffer, fp);
89 if (!continued) { /* Check to see if we're updating this line. */
90 if (strncmp(username, buffer, strlen(username)) == 0) {
91 /* we have a match. */
92 pw_rest = strchr(buffer, ':');
93 *pw_rest++ = '\0';
94 pw_rest = strchr(pw_rest, ':');
95 fprintf(out_fp, "%s:%s%s", buffer, crypt_pw, pw_rest);
96 } else {
97 fputs(buffer, out_fp);
98 }
99 } else {
100 fputs(buffer, out_fp);
101 }
102 if (buffer[strlen(buffer) - 1] == '\n') {
103 continued = 0;
104 } else {
105 continued = 1;
106 }
107 memset(buffer, 0, sizeof buffer);
108 }
109 229
110 if (fflush(out_fp) || fsync(fileno(out_fp)) || fclose(out_fp)) { 230 close_old_fp:
111 unlink(buf); 231 fclose(old_fp);
112 fcntl(fileno(fp), F_SETLK, &lock); 232
113 fclose(fp); 233 free_mem:
114 return 1; 234 if (ENABLE_FEATURE_CLEAN_UP) free(new_name);
115 } 235 if (ENABLE_FEATURE_CLEAN_UP) free((char*)username);
116 if (rename(buf, filename) < 0) { 236 return ret;
117 fcntl(fileno(fp), F_SETLK, &lock);
118 fclose(fp);
119 return 1;
120 } else {
121 fcntl(fileno(fp), F_SETLK, &lock);
122 fclose(fp);
123 return 0;
124 }
125} 237}
126 238
127 239
@@ -133,79 +245,88 @@ int passwd_main(int argc, char **argv)
133 OPT_unlock = 0x4, /* -u - unlock account */ 245 OPT_unlock = 0x4, /* -u - unlock account */
134 OPT_delete = 0x8, /* -d - delete password */ 246 OPT_delete = 0x8, /* -d - delete password */
135 OPT_lud = 0xe, 247 OPT_lud = 0xe,
248 STATE_ALGO_md5 = 0x10,
249 STATE_ALGO_des = 0x20,
136 }; 250 };
137 unsigned opt; 251 unsigned opt;
138 char *opt_a; 252 char *opt_a = "";
139 int amroot; 253 const char *filename;
140 char *cp;
141 char *np;
142 char *name;
143 char *myname; 254 char *myname;
144 int algo = 1; 255 char *name;
256 char *oldp;
257 char *newp = NULL; /* gcc happiness */
145 const struct passwd *pw; 258 const struct passwd *pw;
259 uid_t myuid;
146 260
147 amroot = (getuid() == 0); 261 openlog("passwd", LOG_NOWAIT, LOG_AUTH);
148 openlog("passwd", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
149 opt = getopt32(argc, argv, "a:lud", &opt_a); 262 opt = getopt32(argc, argv, "a:lud", &opt_a);
150 argc -= optind; 263 argc -= optind;
151 argv += optind; 264 argv += optind;
152 if (opt & OPT_algo) algo = get_algo(opt_a); // -a 265
153 if ((opt & OPT_lud) && (!argc || !amroot)) 266 if (strcasecmp(opt_a, "des") == 0) /* -a */
267 opt |= STATE_ALGO_des;
268 else
269 opt |= STATE_ALGO_md5;
270 myuid = getuid();
271 if ((opt & OPT_lud) && (!argc || myuid))
154 bb_show_usage(); 272 bb_show_usage();
155 273
156 myname = xstrdup(bb_getpwuid(NULL, getuid(), -1)); 274 myname = xstrdup(bb_getpwuid(NULL, myuid, -1));
157 name = myname; 275 name = myname;
158 if (argc) name = argv[0]; 276 if (argc) name = argv[0];
159 277
160 pw = getpwnam(name); 278 pw = getpwnam(name);
161 if (!pw) { 279 if (!pw) bb_error_msg_and_die("unknown user %s", name);
162 bb_error_msg_and_die("unknown user %s", name); 280 if (myuid && pw->pw_uid != myuid) {
163 }
164 if (!amroot && pw->pw_uid != getuid()) {
165 syslog(LOG_WARNING, "can't change pwd for '%s'", name); 281 syslog(LOG_WARNING, "can't change pwd for '%s'", name);
166 bb_error_msg_and_die("permission denied"); 282 bb_error_msg_and_die("permission denied");
167 } 283 }
284
285 filename = bb_path_passwd_file;
286 oldp = pw->pw_passwd;
168 if (ENABLE_FEATURE_SHADOWPASSWDS) { 287 if (ENABLE_FEATURE_SHADOWPASSWDS) {
169 struct spwd *sp = getspnam(name); 288 struct spwd *sp = getspnam(name);
170 if (!sp) bb_error_msg_and_die("unknown user %s", name); 289 if (!sp) {
171 cp = sp->sp_pwdp; 290 bb_error_msg("no shadow record for user %s found, "
172 } else cp = pw->pw_passwd; 291 "changing ordinary password instead", name);
292 } else {
293 filename = bb_path_shadow_file;
294 oldp = sp->sp_pwdp;
295 }
296 }
173 297
174 np = name; 298 /* Decide what the new password will be */
175 safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));
176 if (!(opt & OPT_lud)) { 299 if (!(opt & OPT_lud)) {
177 if (!amroot) { 300 if (myuid) {
178 if (cp[0] == '!') { 301 if (oldp[0] == '!') {
179 syslog(LOG_WARNING, "password locked for '%s'", np); 302 syslog(LOG_WARNING, "password locked for '%s'", name);
180 bb_error_msg_and_die("the password for %s cannot be changed", np); 303 bb_error_msg_and_die("the password for %s cannot be changed", name);
181 } 304 }
182 } 305 }
183 printf("Changing password for %s\n", name); 306 printf("Changing password for %s\n", name);
184 if (new_password(pw, amroot, algo)) { 307 newp = new_password(pw, oldp,
308 myuid,
309 opt & STATE_ALGO_md5);
310 if (!newp) {
185 bb_error_msg_and_die("the password for %s is unchanged", name); 311 bb_error_msg_and_die("the password for %s is unchanged", name);
186 } 312 }
187 } else if (opt & OPT_lock) { 313 } else if (opt & OPT_lock) {
188 if (crypt_passwd[0] != '!') { 314 if (oldp[0] == '!') goto skip;
189 memmove(&crypt_passwd[1], crypt_passwd, 315 newp = xasprintf("!%s", oldp);
190 sizeof crypt_passwd - 1);
191 crypt_passwd[sizeof crypt_passwd - 1] = '\0';
192 crypt_passwd[0] = '!';
193 }
194 } else if (opt & OPT_unlock) { 316 } else if (opt & OPT_unlock) {
195 if (crypt_passwd[0] == '!') { 317 if (oldp[0] != '!') goto skip;
196 memmove(crypt_passwd, &crypt_passwd[1], 318 newp = xstrdup(oldp + 1);
197 sizeof crypt_passwd - 1);
198 }
199 } else if (opt & OPT_delete) { 319 } else if (opt & OPT_delete) {
200 crypt_passwd[0] = '\0'; 320 newp = xstrdup("");
201 } 321 }
322
202 set_filesize_limit(30000); 323 set_filesize_limit(30000);
203 signal(SIGHUP, SIG_IGN); 324 signal(SIGHUP, SIG_IGN);
204 signal(SIGINT, SIG_IGN); 325 signal(SIGINT, SIG_IGN);
205 signal(SIGQUIT, SIG_IGN); 326 signal(SIGQUIT, SIG_IGN);
206 umask(077); 327 umask(077);
207 xsetuid(0); 328 xsetuid(0);
208 if (!update_passwd(pw, crypt_passwd)) { 329 if (update_passwd(filename, name, newp) == 0) {
209 syslog(LOG_INFO, "password for '%s' changed by user '%s'", name, 330 syslog(LOG_INFO, "password for '%s' changed by user '%s'", name,
210 myname); 331 myname);
211 puts("Password changed"); 332 puts("Password changed");
@@ -213,164 +334,9 @@ int passwd_main(int argc, char **argv)
213 syslog(LOG_WARNING, "cannot update password file"); 334 syslog(LOG_WARNING, "cannot update password file");
214 bb_error_msg_and_die("cannot update password file"); 335 bb_error_msg_and_die("cannot update password file");
215 } 336 }
216 if (ENABLE_FEATURE_CLEAN_UP) free(myname);
217 return 0;
218}
219
220
221
222static int create_backup(const char *backup, FILE * fp)
223{
224 struct stat sb;
225 struct utimbuf ub;
226 FILE *bkfp;
227 int c, mask;
228
229 if (fstat(fileno(fp), &sb))
230 /* return -1; */
231 return 1;
232
233 mask = umask(077);
234 bkfp = fopen(backup, "w");
235 umask(mask);
236 if (!bkfp)
237 /* return -1; */
238 return 1;
239
240 /* TODO: faster copy, not one-char-at-a-time. --marekm */
241 rewind(fp);
242 while ((c = getc(fp)) != EOF) {
243 if (putc(c, bkfp) == EOF)
244 break;
245 }
246 if (c != EOF || fflush(bkfp)) {
247 fclose(bkfp);
248 /* return -1; */
249 return 1;
250 }
251 if (fclose(bkfp))
252 /* return -1; */
253 return 1;
254 337
255 ub.actime = sb.st_atime; 338 if (ENABLE_FEATURE_CLEAN_UP) free(newp);
256 ub.modtime = sb.st_mtime; 339skip:
257 utime(backup, &ub); 340 if (ENABLE_FEATURE_CLEAN_UP) free(myname);
258 return 0;
259}
260
261static int i64c(int i)
262{
263 if (i <= 0)
264 return '.';
265 if (i == 1)
266 return '/';
267 if (i >= 2 && i < 12)
268 return ('0' - 2 + i);
269 if (i >= 12 && i < 38)
270 return ('A' - 12 + i);
271 if (i >= 38 && i < 63)
272 return ('a' - 38 + i);
273 return 'z';
274}
275
276static char *crypt_make_salt(void)
277{
278 time_t now;
279 static unsigned long x;
280 static char result[3];
281
282 time(&now);
283 x += now + getpid() + clock();
284 result[0] = i64c(((x >> 18) ^ (x >> 6)) & 077);
285 result[1] = i64c(((x >> 12) ^ x) & 077);
286 result[2] = '\0';
287 return result;
288}
289
290
291static int new_password(const struct passwd *pw, int amroot, int algo)
292{
293 char *clear;
294 char *cipher;
295 char *cp;
296 char salt[12]; /* "$N$XXXXXXXX" or "XX" */
297 char orig[200];
298 char pass[200];
299
300 if (!amroot && crypt_passwd[0]) {
301 clear = bb_askpass(0, "Old password:");
302 if (!clear) {
303 /* return -1; */
304 return 1;
305 }
306 cipher = pw_encrypt(clear, crypt_passwd);
307 if (strcmp(cipher, crypt_passwd) != 0) {
308 syslog(LOG_WARNING, "incorrect password for '%s'",
309 pw->pw_name);
310 bb_do_delay(FAIL_DELAY);
311 puts("Incorrect password");
312 /* return -1; */
313 return 1;
314 }
315 safe_strncpy(orig, clear, sizeof(orig));
316 memset(clear, 0, strlen(clear));
317 memset(cipher, 0, strlen(cipher));
318 } else {
319 orig[0] = '\0';
320 }
321 cp = bb_askpass(0, "Enter the new password (minimum of 5 characters).\n"
322 "Please use a combination of upper and lower case letters and numbers.\n"
323 "Enter new password: ");
324 if (!cp ) {
325 memset(orig, 0, sizeof orig);
326 /* return -1; */
327 return 1;
328 }
329 safe_strncpy(pass, cp, sizeof(pass));
330 memset(cp, 0, strlen(cp));
331 /* if (!obscure(orig, pass, pw)) { */
332 if (obscure(orig, pass, pw)) {
333 if (amroot) {
334 puts("\nWarning: weak password (continuing)");
335 } else {
336 /* return -1; */
337 return 1;
338 }
339 }
340 cp = bb_askpass(0, "Re-enter new password: ");
341 if (!cp) {
342 memset(orig, 0, sizeof orig);
343 /* return -1; */
344 return 1;
345 }
346 if (strcmp(cp, pass)) {
347 puts("Passwords do not match");
348 /* return -1; */
349 return 1;
350 }
351 memset(cp, 0, strlen(cp));
352 memset(orig, 0, sizeof(orig));
353 memset(salt, 0, sizeof(salt));
354
355 if (algo == 1) {
356 strcpy(salt, "$1$");
357 strcat(salt, crypt_make_salt());
358 strcat(salt, crypt_make_salt());
359 strcat(salt, crypt_make_salt());
360 }
361
362 strcat(salt, crypt_make_salt());
363 cp = pw_encrypt(pass, salt);
364
365 memset(pass, 0, sizeof pass);
366 safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));
367 return 0; 341 return 0;
368} 342}
369
370static void set_filesize_limit(int blocks)
371{
372 struct rlimit rlimit_fsize;
373
374 rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;
375 setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
376}