1 1.33 kamil /* $NetBSD: login_cap.c,v 1.33 2015/10/29 20:29:24 kamil Exp $ */ 2 1.1 mjl 3 1.1 mjl /*- 4 1.1 mjl * Copyright (c) 1995,1997 Berkeley Software Design, Inc. All rights reserved. 5 1.1 mjl * 6 1.1 mjl * Redistribution and use in source and binary forms, with or without 7 1.1 mjl * modification, are permitted provided that the following conditions 8 1.1 mjl * are met: 9 1.1 mjl * 1. Redistributions of source code must retain the above copyright 10 1.1 mjl * notice, this list of conditions and the following disclaimer. 11 1.1 mjl * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 mjl * notice, this list of conditions and the following disclaimer in the 13 1.1 mjl * documentation and/or other materials provided with the distribution. 14 1.1 mjl * 3. All advertising materials mentioning features or use of this software 15 1.1 mjl * must display the following acknowledgement: 16 1.1 mjl * This product includes software developed by Berkeley Software Design, 17 1.1 mjl * Inc. 18 1.1 mjl * 4. The name of Berkeley Software Design, Inc. may not be used to endorse 19 1.1 mjl * or promote products derived from this software without specific prior 20 1.1 mjl * written permission. 21 1.1 mjl * 22 1.1 mjl * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND 23 1.1 mjl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 mjl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 mjl * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE 26 1.1 mjl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 mjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 mjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 mjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 mjl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 mjl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 mjl * SUCH DAMAGE. 33 1.1 mjl * 34 1.1 mjl * BSDI login_cap.c,v 2.13 1998/02/07 03:17:05 prb Exp 35 1.1 mjl */ 36 1.6 ad 37 1.6 ad #include <sys/cdefs.h> 38 1.6 ad #if defined(LIBC_SCCS) && !defined(lint) 39 1.33 kamil __RCSID("$NetBSD: login_cap.c,v 1.33 2015/10/29 20:29:24 kamil Exp $"); 40 1.6 ad #endif /* LIBC_SCCS and not lint */ 41 1.1 mjl 42 1.1 mjl #include <sys/types.h> 43 1.1 mjl #include <sys/stat.h> 44 1.1 mjl #include <sys/time.h> 45 1.1 mjl #include <sys/resource.h> 46 1.27 elad #include <sys/param.h> 47 1.1 mjl 48 1.10 lukem #include <assert.h> 49 1.4 mjl #include <ctype.h> 50 1.1 mjl #include <err.h> 51 1.1 mjl #include <errno.h> 52 1.1 mjl #include <fcntl.h> 53 1.1 mjl #include <limits.h> 54 1.1 mjl #include <login_cap.h> 55 1.1 mjl #include <paths.h> 56 1.1 mjl #include <pwd.h> 57 1.1 mjl #include <stdio.h> 58 1.1 mjl #include <stdlib.h> 59 1.1 mjl #include <string.h> 60 1.1 mjl #include <syslog.h> 61 1.1 mjl #include <unistd.h> 62 1.7 ad #include <util.h> 63 1.1 mjl 64 1.6 ad static u_quad_t multiply(u_quad_t, u_quad_t); 65 1.19 christos static u_quad_t strtolimit(const char *, char **, int); 66 1.19 christos static u_quad_t strtosize(const char *, char **, int); 67 1.19 christos static int gsetrl(login_cap_t *, int, const char *, int type); 68 1.6 ad static int isinfinite(const char *); 69 1.23 christos static int envset(void *, const char *, const char *, int); 70 1.1 mjl 71 1.1 mjl login_cap_t * 72 1.19 christos login_getclass(const char *class) 73 1.1 mjl { 74 1.17 christos const char *classfiles[2]; 75 1.1 mjl login_cap_t *lc; 76 1.1 mjl int res; 77 1.1 mjl 78 1.10 lukem /* class may be NULL */ 79 1.10 lukem 80 1.9 itojun if (secure_path(_PATH_LOGIN_CONF) == 0) { 81 1.9 itojun classfiles[0] = _PATH_LOGIN_CONF; 82 1.9 itojun classfiles[1] = NULL; 83 1.9 itojun } else { 84 1.9 itojun classfiles[0] = NULL; 85 1.9 itojun } 86 1.1 mjl 87 1.1 mjl if ((lc = malloc(sizeof(login_cap_t))) == NULL) { 88 1.1 mjl syslog(LOG_ERR, "%s:%d malloc: %m", __FILE__, __LINE__); 89 1.1 mjl return (0); 90 1.1 mjl } 91 1.1 mjl 92 1.1 mjl lc->lc_cap = 0; 93 1.1 mjl lc->lc_style = 0; 94 1.1 mjl 95 1.1 mjl if (class == NULL || class[0] == '\0') 96 1.1 mjl class = LOGIN_DEFCLASS; 97 1.1 mjl 98 1.1 mjl if ((lc->lc_class = strdup(class)) == NULL) { 99 1.1 mjl syslog(LOG_ERR, "%s:%d strdup: %m", __FILE__, __LINE__); 100 1.1 mjl free(lc); 101 1.1 mjl return (0); 102 1.1 mjl } 103 1.9 itojun 104 1.9 itojun /* 105 1.9 itojun * Not having a login.conf file is not an error condition. 106 1.9 itojun * The individual routines deal reasonably with missing 107 1.9 itojun * capabilities and use default values. 108 1.9 itojun */ 109 1.9 itojun if (classfiles[0] == NULL) 110 1.9 itojun return(lc); 111 1.1 mjl 112 1.8 itojun if ((res = cgetent(&lc->lc_cap, classfiles, lc->lc_class)) != 0) { 113 1.1 mjl lc->lc_cap = 0; 114 1.1 mjl switch (res) { 115 1.1 mjl case 1: 116 1.1 mjl syslog(LOG_ERR, "%s: couldn't resolve 'tc'", 117 1.1 mjl lc->lc_class); 118 1.1 mjl break; 119 1.1 mjl case -1: 120 1.21 drochner if (strcmp(lc->lc_class, LOGIN_DEFCLASS) == 0) 121 1.1 mjl return (lc); 122 1.1 mjl syslog(LOG_ERR, "%s: unknown class", lc->lc_class); 123 1.1 mjl break; 124 1.1 mjl case -2: 125 1.1 mjl syslog(LOG_ERR, "%s: getting class information: %m", 126 1.1 mjl lc->lc_class); 127 1.1 mjl break; 128 1.1 mjl case -3: 129 1.1 mjl syslog(LOG_ERR, "%s: 'tc' reference loop", 130 1.1 mjl lc->lc_class); 131 1.1 mjl break; 132 1.1 mjl default: 133 1.1 mjl syslog(LOG_ERR, "%s: unexpected cgetent error", 134 1.1 mjl lc->lc_class); 135 1.1 mjl break; 136 1.1 mjl } 137 1.1 mjl free(lc->lc_class); 138 1.1 mjl free(lc); 139 1.1 mjl return (0); 140 1.1 mjl } 141 1.1 mjl return (lc); 142 1.1 mjl } 143 1.1 mjl 144 1.4 mjl login_cap_t * 145 1.6 ad login_getpwclass(const struct passwd *pwd) 146 1.4 mjl { 147 1.10 lukem 148 1.10 lukem /* pwd may be NULL */ 149 1.10 lukem 150 1.4 mjl return login_getclass(pwd ? pwd->pw_class : NULL); 151 1.4 mjl } 152 1.4 mjl 153 1.1 mjl char * 154 1.19 christos login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *e) 155 1.1 mjl { 156 1.13 itojun char *res = NULL; 157 1.1 mjl int status; 158 1.1 mjl 159 1.1 mjl errno = 0; 160 1.1 mjl 161 1.10 lukem _DIAGASSERT(cap != NULL); 162 1.10 lukem 163 1.2 mjl if (!lc || !lc->lc_cap) 164 1.1 mjl return (def); 165 1.1 mjl 166 1.1 mjl switch (status = cgetstr(lc->lc_cap, cap, &res)) { 167 1.1 mjl case -1: 168 1.12 itojun if (res) 169 1.12 itojun free(res); 170 1.1 mjl return (def); 171 1.1 mjl case -2: 172 1.1 mjl syslog(LOG_ERR, "%s: getting capability %s: %m", 173 1.1 mjl lc->lc_class, cap); 174 1.12 itojun if (res) 175 1.12 itojun free(res); 176 1.1 mjl return (e); 177 1.1 mjl default: 178 1.1 mjl if (status >= 0) 179 1.1 mjl return (res); 180 1.1 mjl syslog(LOG_ERR, "%s: unexpected error with capability %s", 181 1.1 mjl lc->lc_class, cap); 182 1.12 itojun if (res) 183 1.12 itojun free(res); 184 1.1 mjl return (e); 185 1.1 mjl } 186 1.1 mjl } 187 1.1 mjl 188 1.1 mjl quad_t 189 1.19 christos login_getcaptime(login_cap_t *lc, const char *cap, quad_t def, quad_t e) 190 1.1 mjl { 191 1.1 mjl char *ep; 192 1.13 itojun char *res = NULL, *sres; 193 1.1 mjl int status; 194 1.1 mjl quad_t q, r; 195 1.1 mjl 196 1.10 lukem _DIAGASSERT(cap != NULL); 197 1.10 lukem 198 1.1 mjl errno = 0; 199 1.2 mjl if (!lc || !lc->lc_cap) 200 1.1 mjl return (def); 201 1.1 mjl 202 1.1 mjl switch (status = cgetstr(lc->lc_cap, cap, &res)) { 203 1.1 mjl case -1: 204 1.12 itojun if (res) 205 1.12 itojun free(res); 206 1.1 mjl return (def); 207 1.1 mjl case -2: 208 1.1 mjl syslog(LOG_ERR, "%s: getting capability %s: %m", 209 1.1 mjl lc->lc_class, cap); 210 1.1 mjl errno = ERANGE; 211 1.12 itojun if (res) 212 1.12 itojun free(res); 213 1.1 mjl return (e); 214 1.1 mjl default: 215 1.1 mjl if (status >= 0) 216 1.1 mjl break; 217 1.1 mjl syslog(LOG_ERR, "%s: unexpected error with capability %s", 218 1.1 mjl lc->lc_class, cap); 219 1.1 mjl errno = ERANGE; 220 1.12 itojun if (res) 221 1.12 itojun free(res); 222 1.1 mjl return (e); 223 1.1 mjl } 224 1.1 mjl 225 1.5 mjl if (isinfinite(res)) 226 1.1 mjl return (RLIM_INFINITY); 227 1.1 mjl 228 1.1 mjl errno = 0; 229 1.1 mjl 230 1.1 mjl q = 0; 231 1.1 mjl sres = res; 232 1.1 mjl while (*res) { 233 1.1 mjl r = strtoq(res, &ep, 0); 234 1.1 mjl if (!ep || ep == res || 235 1.1 mjl ((r == QUAD_MIN || r == QUAD_MAX) && errno == ERANGE)) { 236 1.1 mjl invalid: 237 1.1 mjl syslog(LOG_ERR, "%s:%s=%s: invalid time", 238 1.1 mjl lc->lc_class, cap, sres); 239 1.1 mjl errno = ERANGE; 240 1.12 itojun free(sres); 241 1.1 mjl return (e); 242 1.1 mjl } 243 1.1 mjl switch (*ep++) { 244 1.1 mjl case '\0': 245 1.1 mjl --ep; 246 1.1 mjl break; 247 1.1 mjl case 's': case 'S': 248 1.1 mjl break; 249 1.1 mjl case 'm': case 'M': 250 1.1 mjl r *= 60; 251 1.1 mjl break; 252 1.1 mjl case 'h': case 'H': 253 1.1 mjl r *= 60 * 60; 254 1.1 mjl break; 255 1.1 mjl case 'd': case 'D': 256 1.1 mjl r *= 60 * 60 * 24; 257 1.1 mjl break; 258 1.1 mjl case 'w': case 'W': 259 1.1 mjl r *= 60 * 60 * 24 * 7; 260 1.1 mjl break; 261 1.1 mjl case 'y': case 'Y': /* Pretty absurd */ 262 1.1 mjl r *= 60 * 60 * 24 * 365; 263 1.1 mjl break; 264 1.1 mjl default: 265 1.1 mjl goto invalid; 266 1.1 mjl } 267 1.1 mjl res = ep; 268 1.1 mjl q += r; 269 1.1 mjl } 270 1.12 itojun free(sres); 271 1.1 mjl return (q); 272 1.1 mjl } 273 1.1 mjl 274 1.1 mjl quad_t 275 1.19 christos login_getcapnum(login_cap_t *lc, const char *cap, quad_t def, quad_t e) 276 1.1 mjl { 277 1.1 mjl char *ep; 278 1.13 itojun char *res = NULL; 279 1.1 mjl int status; 280 1.1 mjl quad_t q; 281 1.1 mjl 282 1.10 lukem _DIAGASSERT(cap != NULL); 283 1.10 lukem 284 1.1 mjl errno = 0; 285 1.2 mjl if (!lc || !lc->lc_cap) 286 1.1 mjl return (def); 287 1.1 mjl 288 1.1 mjl switch (status = cgetstr(lc->lc_cap, cap, &res)) { 289 1.1 mjl case -1: 290 1.12 itojun if (res) 291 1.12 itojun free(res); 292 1.1 mjl return (def); 293 1.1 mjl case -2: 294 1.1 mjl syslog(LOG_ERR, "%s: getting capability %s: %m", 295 1.1 mjl lc->lc_class, cap); 296 1.1 mjl errno = ERANGE; 297 1.12 itojun if (res) 298 1.12 itojun free(res); 299 1.1 mjl return (e); 300 1.1 mjl default: 301 1.1 mjl if (status >= 0) 302 1.1 mjl break; 303 1.1 mjl syslog(LOG_ERR, "%s: unexpected error with capability %s", 304 1.1 mjl lc->lc_class, cap); 305 1.1 mjl errno = ERANGE; 306 1.12 itojun if (res) 307 1.12 itojun free(res); 308 1.1 mjl return (e); 309 1.1 mjl } 310 1.1 mjl 311 1.5 mjl if (isinfinite(res)) 312 1.1 mjl return (RLIM_INFINITY); 313 1.1 mjl 314 1.1 mjl errno = 0; 315 1.1 mjl q = strtoq(res, &ep, 0); 316 1.1 mjl if (!ep || ep == res || ep[0] || 317 1.1 mjl ((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) { 318 1.1 mjl syslog(LOG_ERR, "%s:%s=%s: invalid number", 319 1.1 mjl lc->lc_class, cap, res); 320 1.1 mjl errno = ERANGE; 321 1.12 itojun free(res); 322 1.1 mjl return (e); 323 1.1 mjl } 324 1.12 itojun free(res); 325 1.1 mjl return (q); 326 1.1 mjl } 327 1.1 mjl 328 1.1 mjl quad_t 329 1.19 christos login_getcapsize(login_cap_t *lc, const char *cap, quad_t def, quad_t e) 330 1.1 mjl { 331 1.1 mjl char *ep; 332 1.13 itojun char *res = NULL; 333 1.1 mjl int status; 334 1.1 mjl quad_t q; 335 1.1 mjl 336 1.10 lukem _DIAGASSERT(cap != NULL); 337 1.10 lukem 338 1.1 mjl errno = 0; 339 1.1 mjl 340 1.2 mjl if (!lc || !lc->lc_cap) 341 1.1 mjl return (def); 342 1.1 mjl 343 1.1 mjl switch (status = cgetstr(lc->lc_cap, cap, &res)) { 344 1.1 mjl case -1: 345 1.12 itojun if (res) 346 1.12 itojun free(res); 347 1.1 mjl return (def); 348 1.1 mjl case -2: 349 1.1 mjl syslog(LOG_ERR, "%s: getting capability %s: %m", 350 1.1 mjl lc->lc_class, cap); 351 1.1 mjl errno = ERANGE; 352 1.12 itojun if (res) 353 1.12 itojun free(res); 354 1.1 mjl return (e); 355 1.1 mjl default: 356 1.1 mjl if (status >= 0) 357 1.1 mjl break; 358 1.1 mjl syslog(LOG_ERR, "%s: unexpected error with capability %s", 359 1.1 mjl lc->lc_class, cap); 360 1.1 mjl errno = ERANGE; 361 1.12 itojun if (res) 362 1.12 itojun free(res); 363 1.1 mjl return (e); 364 1.1 mjl } 365 1.1 mjl 366 1.1 mjl errno = 0; 367 1.1 mjl q = strtolimit(res, &ep, 0); 368 1.1 mjl if (!ep || ep == res || (ep[0] && ep[1]) || 369 1.1 mjl ((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) { 370 1.1 mjl syslog(LOG_ERR, "%s:%s=%s: invalid size", 371 1.1 mjl lc->lc_class, cap, res); 372 1.1 mjl errno = ERANGE; 373 1.12 itojun free(res); 374 1.1 mjl return (e); 375 1.1 mjl } 376 1.12 itojun free(res); 377 1.1 mjl return (q); 378 1.1 mjl } 379 1.1 mjl 380 1.1 mjl int 381 1.19 christos login_getcapbool(login_cap_t *lc, const char *cap, u_int def) 382 1.1 mjl { 383 1.10 lukem 384 1.10 lukem _DIAGASSERT(cap != NULL); 385 1.10 lukem 386 1.2 mjl if (!lc || !lc->lc_cap) 387 1.1 mjl return (def); 388 1.1 mjl 389 1.1 mjl return (cgetcap(lc->lc_cap, cap, ':') != NULL); 390 1.1 mjl } 391 1.1 mjl 392 1.1 mjl void 393 1.6 ad login_close(login_cap_t *lc) 394 1.1 mjl { 395 1.10 lukem 396 1.1 mjl if (lc) { 397 1.1 mjl if (lc->lc_class) 398 1.1 mjl free(lc->lc_class); 399 1.1 mjl if (lc->lc_cap) 400 1.1 mjl free(lc->lc_cap); 401 1.1 mjl if (lc->lc_style) 402 1.1 mjl free(lc->lc_style); 403 1.1 mjl free(lc); 404 1.1 mjl } 405 1.1 mjl } 406 1.1 mjl 407 1.7 ad #define R_CTIME 1 408 1.7 ad #define R_CSIZE 2 409 1.7 ad #define R_CNUMB 3 410 1.1 mjl 411 1.1 mjl static struct { 412 1.1 mjl int what; 413 1.1 mjl int type; 414 1.19 christos const char *name; 415 1.1 mjl } r_list[] = { 416 1.7 ad { RLIMIT_CPU, R_CTIME, "cputime", }, 417 1.7 ad { RLIMIT_FSIZE, R_CSIZE, "filesize", }, 418 1.7 ad { RLIMIT_DATA, R_CSIZE, "datasize", }, 419 1.7 ad { RLIMIT_STACK, R_CSIZE, "stacksize", }, 420 1.7 ad { RLIMIT_RSS, R_CSIZE, "memoryuse", }, 421 1.7 ad { RLIMIT_MEMLOCK, R_CSIZE, "memorylocked", }, 422 1.7 ad { RLIMIT_NPROC, R_CNUMB, "maxproc", }, 423 1.31 yamt { RLIMIT_NTHR, R_CNUMB, "maxthread", }, 424 1.7 ad { RLIMIT_NOFILE, R_CNUMB, "openfiles", }, 425 1.7 ad { RLIMIT_CORE, R_CSIZE, "coredumpsize", }, 426 1.18 lukem { RLIMIT_SBSIZE, R_CSIZE, "sbsize", }, 427 1.32 kamil { RLIMIT_AS, R_CSIZE, "vmemoryuse", }, 428 1.1 mjl { -1, 0, 0 } 429 1.1 mjl }; 430 1.1 mjl 431 1.1 mjl static int 432 1.19 christos gsetrl(login_cap_t *lc, int what, const char *name, int type) 433 1.1 mjl { 434 1.1 mjl struct rlimit rl; 435 1.1 mjl struct rlimit r; 436 1.1 mjl char name_cur[32]; 437 1.1 mjl char name_max[32]; 438 1.1 mjl 439 1.10 lukem _DIAGASSERT(name != NULL); 440 1.10 lukem 441 1.25 christos (void)snprintf(name_cur, sizeof(name_cur), "%s-cur", name); 442 1.25 christos (void)snprintf(name_max, sizeof(name_max), "%s-max", name); 443 1.1 mjl 444 1.1 mjl if (getrlimit(what, &r)) { 445 1.1 mjl syslog(LOG_ERR, "getting resource limit: %m"); 446 1.1 mjl return (-1); 447 1.1 mjl } 448 1.1 mjl 449 1.30 christos #define RCUR ((quad_t)r.rlim_cur) 450 1.30 christos #define RMAX ((quad_t)r.rlim_max) 451 1.1 mjl 452 1.1 mjl switch (type) { 453 1.7 ad case R_CTIME: 454 1.30 christos r.rlim_cur = login_getcaptime(lc, name, RCUR, RCUR); 455 1.30 christos r.rlim_max = login_getcaptime(lc, name, RMAX, RMAX); 456 1.1 mjl rl.rlim_cur = login_getcaptime(lc, name_cur, RCUR, RCUR); 457 1.1 mjl rl.rlim_max = login_getcaptime(lc, name_max, RMAX, RMAX); 458 1.1 mjl break; 459 1.7 ad case R_CSIZE: 460 1.30 christos r.rlim_cur = login_getcapsize(lc, name, RCUR, RCUR); 461 1.30 christos r.rlim_max = login_getcapsize(lc, name, RMAX, RMAX); 462 1.1 mjl rl.rlim_cur = login_getcapsize(lc, name_cur, RCUR, RCUR); 463 1.1 mjl rl.rlim_max = login_getcapsize(lc, name_max, RMAX, RMAX); 464 1.1 mjl break; 465 1.7 ad case R_CNUMB: 466 1.30 christos r.rlim_cur = login_getcapnum(lc, name, RCUR, RCUR); 467 1.30 christos r.rlim_max = login_getcapnum(lc, name, RMAX, RMAX); 468 1.1 mjl rl.rlim_cur = login_getcapnum(lc, name_cur, RCUR, RCUR); 469 1.1 mjl rl.rlim_max = login_getcapnum(lc, name_max, RMAX, RMAX); 470 1.1 mjl break; 471 1.1 mjl default: 472 1.25 christos syslog(LOG_ERR, "%s: invalid type %d setting resource limit %s", 473 1.25 christos lc->lc_class, type, name); 474 1.1 mjl return (-1); 475 1.1 mjl } 476 1.1 mjl 477 1.1 mjl if (setrlimit(what, &rl)) { 478 1.1 mjl syslog(LOG_ERR, "%s: setting resource limit %s: %m", 479 1.1 mjl lc->lc_class, name); 480 1.1 mjl return (-1); 481 1.1 mjl } 482 1.1 mjl #undef RCUR 483 1.1 mjl #undef RMAX 484 1.1 mjl return (0); 485 1.1 mjl } 486 1.1 mjl 487 1.4 mjl static int 488 1.23 christos /*ARGSUSED*/ 489 1.26 christos envset(void *envp __unused, const char *name, const char *value, int overwrite) 490 1.23 christos { 491 1.23 christos return setenv(name, value, overwrite); 492 1.23 christos } 493 1.23 christos 494 1.23 christos int 495 1.23 christos setuserenv(login_cap_t *lc, envfunc_t senv, void *envp) 496 1.4 mjl { 497 1.19 christos const char *stop = ", \t"; 498 1.24 christos size_t i, count; 499 1.4 mjl char *ptr; 500 1.4 mjl char **res; 501 1.4 mjl char *str = login_getcapstr(lc, "setenv", NULL, NULL); 502 1.4 mjl 503 1.8 itojun if (str == NULL || *str == '\0') 504 1.4 mjl return 0; 505 1.4 mjl 506 1.24 christos /* 507 1.24 christos * count the sub-strings, this may over-count since we don't 508 1.24 christos * account for escaped delimiters. 509 1.24 christos */ 510 1.4 mjl for (i = 1, ptr = str; *ptr; i++) { 511 1.4 mjl ptr += strcspn(ptr, stop); 512 1.4 mjl if (*ptr) 513 1.4 mjl ptr++; 514 1.8 itojun } 515 1.4 mjl 516 1.4 mjl /* allocate ptr array and string */ 517 1.4 mjl count = i; 518 1.30 christos res = malloc(count * sizeof(*res) + strlen(str) + 1); 519 1.4 mjl 520 1.8 itojun if (!res) 521 1.4 mjl return -1; 522 1.4 mjl 523 1.24 christos ptr = (char *)(void *)&res[count]; 524 1.24 christos (void)strcpy(ptr, str); 525 1.4 mjl 526 1.4 mjl /* split string */ 527 1.24 christos for (i = 0; (res[i] = stresep(&ptr, stop, '\\')) != NULL; ) 528 1.24 christos if (*res[i]) 529 1.24 christos i++; 530 1.4 mjl 531 1.24 christos count = i; 532 1.4 mjl 533 1.24 christos for (i = 0; i < count; i++) { 534 1.24 christos if ((ptr = strchr(res[i], '=')) != NULL) 535 1.24 christos *ptr++ = '\0'; 536 1.24 christos else 537 1.24 christos ptr = NULL; 538 1.24 christos (void)(*senv)(envp, res[i], ptr ? ptr : "", 1); 539 1.4 mjl } 540 1.4 mjl 541 1.5 mjl free(res); 542 1.4 mjl return 0; 543 1.4 mjl } 544 1.4 mjl 545 1.1 mjl int 546 1.19 christos setclasscontext(const char *class, u_int flags) 547 1.1 mjl { 548 1.1 mjl int ret; 549 1.1 mjl login_cap_t *lc; 550 1.1 mjl 551 1.1 mjl flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY | LOGIN_SETUMASK | 552 1.1 mjl LOGIN_SETPATH; 553 1.1 mjl 554 1.1 mjl lc = login_getclass(class); 555 1.1 mjl ret = lc ? setusercontext(lc, NULL, 0, flags) : -1; 556 1.1 mjl login_close(lc); 557 1.1 mjl return (ret); 558 1.1 mjl } 559 1.1 mjl 560 1.1 mjl int 561 1.6 ad setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, u_int flags) 562 1.1 mjl { 563 1.27 elad char per_user_tmp[MAXPATHLEN + 1]; 564 1.29 mjf const char *component_name; 565 1.1 mjl login_cap_t *flc; 566 1.1 mjl quad_t p; 567 1.1 mjl int i; 568 1.29 mjf ssize_t len; 569 1.1 mjl 570 1.1 mjl flc = NULL; 571 1.1 mjl 572 1.3 mjl if (!lc) 573 1.3 mjl flc = lc = login_getclass(pwd ? pwd->pw_class : NULL); 574 1.1 mjl 575 1.1 mjl /* 576 1.1 mjl * Without the pwd entry being passed we cannot set either 577 1.1 mjl * the group or the login. We could complain about it. 578 1.1 mjl */ 579 1.1 mjl if (pwd == NULL) 580 1.1 mjl flags &= ~(LOGIN_SETGROUP|LOGIN_SETLOGIN); 581 1.1 mjl 582 1.28 christos #ifdef LOGIN_OSETGROUP 583 1.28 christos if (pwd == NULL) 584 1.28 christos flags &= ~LOGIN_OSETGROUP; 585 1.28 christos if (flags & LOGIN_OSETGROUP) 586 1.28 christos flags = (flags & ~LOGIN_OSETGROUP) | LOGIN_SETGROUP; 587 1.28 christos #endif 588 1.1 mjl if (flags & LOGIN_SETRESOURCES) 589 1.1 mjl for (i = 0; r_list[i].name; ++i) 590 1.25 christos (void)gsetrl(lc, r_list[i].what, r_list[i].name, 591 1.25 christos r_list[i].type); 592 1.1 mjl 593 1.1 mjl if (flags & LOGIN_SETPRIORITY) { 594 1.22 elad p = login_getcapnum(lc, "priority", (quad_t)0, (quad_t)0); 595 1.1 mjl 596 1.28 christos if (setpriority(PRIO_PROCESS, 0, (int)p) == -1) 597 1.1 mjl syslog(LOG_ERR, "%s: setpriority: %m", lc->lc_class); 598 1.1 mjl } 599 1.1 mjl 600 1.1 mjl if (flags & LOGIN_SETUMASK) { 601 1.1 mjl p = login_getcapnum(lc, "umask", (quad_t) LOGIN_DEFUMASK, 602 1.28 christos (quad_t)LOGIN_DEFUMASK); 603 1.1 mjl umask((mode_t)p); 604 1.1 mjl } 605 1.1 mjl 606 1.28 christos if (flags & LOGIN_SETGID) { 607 1.28 christos if (setgid(pwd->pw_gid) == -1) { 608 1.1 mjl syslog(LOG_ERR, "setgid(%d): %m", pwd->pw_gid); 609 1.1 mjl login_close(flc); 610 1.1 mjl return (-1); 611 1.1 mjl } 612 1.28 christos } 613 1.1 mjl 614 1.28 christos if (flags & LOGIN_SETGROUPS) { 615 1.28 christos if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { 616 1.1 mjl syslog(LOG_ERR, "initgroups(%s,%d): %m", 617 1.1 mjl pwd->pw_name, pwd->pw_gid); 618 1.1 mjl login_close(flc); 619 1.1 mjl return (-1); 620 1.1 mjl } 621 1.1 mjl } 622 1.1 mjl 623 1.27 elad /* Create per-user temporary directories if needed. */ 624 1.29 mjf if ((len = readlink("/tmp", per_user_tmp, 625 1.29 mjf sizeof(per_user_tmp) - 6)) != -1) { 626 1.29 mjf 627 1.29 mjf static const char atuid[] = "/@ruid"; 628 1.27 elad char *lp; 629 1.27 elad 630 1.29 mjf /* readlink does not nul-terminate the string */ 631 1.29 mjf per_user_tmp[len] = '\0'; 632 1.29 mjf 633 1.27 elad /* Check if it's magic symlink. */ 634 1.27 elad lp = strstr(per_user_tmp, atuid); 635 1.27 elad if (lp != NULL && *(lp + (sizeof(atuid) - 1)) == '\0') { 636 1.27 elad lp++; 637 1.27 elad 638 1.29 mjf if (snprintf(lp, 11, "/%u", pwd->pw_uid) > 10) { 639 1.27 elad syslog(LOG_ERR, "real temporary path too long"); 640 1.27 elad login_close(flc); 641 1.27 elad return (-1); 642 1.27 elad } 643 1.27 elad if (mkdir(per_user_tmp, S_IRWXU) != -1) { 644 1.29 mjf if (chown(per_user_tmp, pwd->pw_uid, 645 1.29 mjf pwd->pw_gid)) { 646 1.29 mjf component_name = "chown"; 647 1.29 mjf goto out; 648 1.29 mjf } 649 1.29 mjf 650 1.29 mjf /* 651 1.29 mjf * Must set sticky bit for tmp directory, some 652 1.29 mjf * programs rely on this. 653 1.29 mjf */ 654 1.29 mjf if(chmod(per_user_tmp, S_IRWXU | S_ISVTX)) { 655 1.29 mjf component_name = "chmod"; 656 1.29 mjf goto out; 657 1.29 mjf } 658 1.27 elad } else { 659 1.29 mjf if (errno != EEXIST) { 660 1.29 mjf component_name = "mkdir"; 661 1.29 mjf goto out; 662 1.29 mjf } else { 663 1.29 mjf /* 664 1.29 mjf * We must ensure that we own the 665 1.29 mjf * directory and that is has the correct 666 1.29 mjf * permissions, otherwise a DOS attack 667 1.29 mjf * is possible. 668 1.29 mjf */ 669 1.29 mjf struct stat sb; 670 1.29 mjf if (stat(per_user_tmp, &sb) == -1) { 671 1.29 mjf component_name = "stat"; 672 1.29 mjf goto out; 673 1.29 mjf } 674 1.29 mjf 675 1.29 mjf if (sb.st_uid != pwd->pw_uid) { 676 1.29 mjf if (chown(per_user_tmp, 677 1.29 mjf pwd->pw_uid, pwd->pw_gid)) { 678 1.29 mjf component_name = "chown"; 679 1.29 mjf goto out; 680 1.29 mjf } 681 1.29 mjf } 682 1.29 mjf 683 1.29 mjf if (sb.st_mode != (S_IRWXU | S_ISVTX)) { 684 1.29 mjf if (chmod(per_user_tmp, 685 1.29 mjf S_IRWXU | S_ISVTX)) { 686 1.29 mjf component_name = "chmod"; 687 1.29 mjf goto out; 688 1.29 mjf } 689 1.29 mjf } 690 1.29 mjf } 691 1.27 elad } 692 1.27 elad } 693 1.27 elad } 694 1.27 elad errno = 0; 695 1.27 elad 696 1.1 mjl if (flags & LOGIN_SETLOGIN) 697 1.28 christos if (setlogin(pwd->pw_name) == -1) { 698 1.1 mjl syslog(LOG_ERR, "setlogin(%s) failure: %m", 699 1.1 mjl pwd->pw_name); 700 1.1 mjl login_close(flc); 701 1.1 mjl return (-1); 702 1.1 mjl } 703 1.1 mjl 704 1.1 mjl if (flags & LOGIN_SETUSER) 705 1.28 christos if (setuid(uid) == -1) { 706 1.1 mjl syslog(LOG_ERR, "setuid(%d): %m", uid); 707 1.1 mjl login_close(flc); 708 1.1 mjl return (-1); 709 1.1 mjl } 710 1.4 mjl 711 1.4 mjl if (flags & LOGIN_SETENV) 712 1.23 christos setuserenv(lc, envset, NULL); 713 1.1 mjl 714 1.1 mjl if (flags & LOGIN_SETPATH) 715 1.23 christos setuserpath(lc, pwd ? pwd->pw_dir : "", envset, NULL); 716 1.1 mjl 717 1.1 mjl login_close(flc); 718 1.1 mjl return (0); 719 1.29 mjf 720 1.29 mjf out: 721 1.29 mjf if (component_name != NULL) { 722 1.29 mjf syslog(LOG_ERR, "%s %s: %m", component_name, per_user_tmp); 723 1.29 mjf login_close(flc); 724 1.29 mjf return (-1); 725 1.29 mjf } else { 726 1.29 mjf syslog(LOG_ERR, "%s: %m", per_user_tmp); 727 1.29 mjf login_close(flc); 728 1.29 mjf return (-1); 729 1.29 mjf } 730 1.1 mjl } 731 1.1 mjl 732 1.23 christos void 733 1.23 christos setuserpath(login_cap_t *lc, const char *home, envfunc_t senv, void *envp) 734 1.1 mjl { 735 1.1 mjl size_t hlen, plen; 736 1.1 mjl int cnt = 0; 737 1.1 mjl char *path; 738 1.19 christos const char *cpath; 739 1.1 mjl char *p, *q; 740 1.1 mjl 741 1.10 lukem _DIAGASSERT(home != NULL); 742 1.10 lukem 743 1.1 mjl hlen = strlen(home); 744 1.1 mjl 745 1.20 christos p = path = login_getcapstr(lc, "path", NULL, NULL); 746 1.1 mjl if (p) { 747 1.1 mjl while (*p) 748 1.1 mjl if (*p++ == '~') 749 1.1 mjl ++cnt; 750 1.1 mjl plen = (p - path) + cnt * (hlen + 1) + 1; 751 1.1 mjl p = path; 752 1.1 mjl q = path = malloc(plen); 753 1.1 mjl if (q) { 754 1.1 mjl while (*p) { 755 1.1 mjl p += strspn(p, " \t"); 756 1.1 mjl if (*p == '\0') 757 1.1 mjl break; 758 1.1 mjl plen = strcspn(p, " \t"); 759 1.1 mjl if (hlen == 0 && *p == '~') { 760 1.1 mjl p += plen; 761 1.1 mjl continue; 762 1.1 mjl } 763 1.1 mjl if (q != path) 764 1.1 mjl *q++ = ':'; 765 1.1 mjl if (*p == '~') { 766 1.1 mjl strcpy(q, home); 767 1.1 mjl q += hlen; 768 1.1 mjl ++p; 769 1.1 mjl --plen; 770 1.1 mjl } 771 1.1 mjl memcpy(q, p, plen); 772 1.1 mjl p += plen; 773 1.1 mjl q += plen; 774 1.1 mjl } 775 1.1 mjl *q = '\0'; 776 1.20 christos cpath = path; 777 1.1 mjl } else 778 1.19 christos cpath = _PATH_DEFPATH; 779 1.1 mjl } else 780 1.19 christos cpath = _PATH_DEFPATH; 781 1.23 christos if ((*senv)(envp, "PATH", cpath, 1)) 782 1.1 mjl warn("could not set PATH"); 783 1.1 mjl } 784 1.1 mjl 785 1.1 mjl /* 786 1.1 mjl * Convert an expression of the following forms 787 1.1 mjl * 1) A number. 788 1.1 mjl * 2) A number followed by a b (mult by 512). 789 1.1 mjl * 3) A number followed by a k (mult by 1024). 790 1.1 mjl * 5) A number followed by a m (mult by 1024 * 1024). 791 1.1 mjl * 6) A number followed by a g (mult by 1024 * 1024 * 1024). 792 1.1 mjl * 7) A number followed by a t (mult by 1024 * 1024 * 1024 * 1024). 793 1.1 mjl * 8) Two or more numbers (with/without k,b,m,g, or t). 794 1.11 wiz * separated by x (also * for backwards compatibility), specifying 795 1.1 mjl * the product of the indicated values. 796 1.1 mjl */ 797 1.6 ad static u_quad_t 798 1.19 christos strtosize(const char *str, char **endptr, int radix) 799 1.1 mjl { 800 1.1 mjl u_quad_t num, num2; 801 1.1 mjl char *expr, *expr2; 802 1.1 mjl 803 1.10 lukem _DIAGASSERT(str != NULL); 804 1.10 lukem /* endptr may be NULL */ 805 1.10 lukem 806 1.1 mjl errno = 0; 807 1.1 mjl num = strtouq(str, &expr, radix); 808 1.1 mjl if (errno || expr == str) { 809 1.1 mjl if (endptr) 810 1.1 mjl *endptr = expr; 811 1.1 mjl return (num); 812 1.1 mjl } 813 1.1 mjl 814 1.1 mjl switch(*expr) { 815 1.1 mjl case 'b': case 'B': 816 1.1 mjl num = multiply(num, (u_quad_t)512); 817 1.1 mjl ++expr; 818 1.1 mjl break; 819 1.1 mjl case 'k': case 'K': 820 1.1 mjl num = multiply(num, (u_quad_t)1024); 821 1.1 mjl ++expr; 822 1.1 mjl break; 823 1.1 mjl case 'm': case 'M': 824 1.1 mjl num = multiply(num, (u_quad_t)1024 * 1024); 825 1.1 mjl ++expr; 826 1.1 mjl break; 827 1.1 mjl case 'g': case 'G': 828 1.1 mjl num = multiply(num, (u_quad_t)1024 * 1024 * 1024); 829 1.1 mjl ++expr; 830 1.1 mjl break; 831 1.1 mjl case 't': case 'T': 832 1.1 mjl num = multiply(num, (u_quad_t)1024 * 1024); 833 1.1 mjl num = multiply(num, (u_quad_t)1024 * 1024); 834 1.1 mjl ++expr; 835 1.1 mjl break; 836 1.1 mjl } 837 1.1 mjl 838 1.1 mjl if (errno) 839 1.1 mjl goto erange; 840 1.1 mjl 841 1.1 mjl switch(*expr) { 842 1.1 mjl case '*': /* Backward compatible. */ 843 1.1 mjl case 'x': 844 1.1 mjl num2 = strtosize(expr+1, &expr2, radix); 845 1.1 mjl if (errno) { 846 1.1 mjl expr = expr2; 847 1.1 mjl goto erange; 848 1.1 mjl } 849 1.1 mjl 850 1.1 mjl if (expr2 == expr + 1) { 851 1.1 mjl if (endptr) 852 1.1 mjl *endptr = expr; 853 1.1 mjl return (num); 854 1.1 mjl } 855 1.1 mjl expr = expr2; 856 1.1 mjl num = multiply(num, num2); 857 1.1 mjl if (errno) 858 1.1 mjl goto erange; 859 1.1 mjl break; 860 1.1 mjl } 861 1.1 mjl if (endptr) 862 1.1 mjl *endptr = expr; 863 1.1 mjl return (num); 864 1.1 mjl erange: 865 1.1 mjl if (endptr) 866 1.1 mjl *endptr = expr; 867 1.1 mjl errno = ERANGE; 868 1.1 mjl return (UQUAD_MAX); 869 1.1 mjl } 870 1.1 mjl 871 1.6 ad static u_quad_t 872 1.19 christos strtolimit(const char *str, char **endptr, int radix) 873 1.1 mjl { 874 1.10 lukem 875 1.10 lukem _DIAGASSERT(str != NULL); 876 1.10 lukem /* endptr may be NULL */ 877 1.10 lukem 878 1.5 mjl if (isinfinite(str)) { 879 1.1 mjl if (endptr) 880 1.19 christos *endptr = (char *)__UNCONST(str) + strlen(str); 881 1.1 mjl return ((u_quad_t)RLIM_INFINITY); 882 1.1 mjl } 883 1.1 mjl return (strtosize(str, endptr, radix)); 884 1.5 mjl } 885 1.5 mjl 886 1.5 mjl static int 887 1.5 mjl isinfinite(const char *s) 888 1.5 mjl { 889 1.5 mjl static const char *infs[] = { 890 1.5 mjl "infinity", 891 1.5 mjl "inf", 892 1.5 mjl "unlimited", 893 1.5 mjl "unlimit", 894 1.5 mjl NULL 895 1.5 mjl }; 896 1.5 mjl const char **i; 897 1.10 lukem 898 1.10 lukem _DIAGASSERT(s != NULL); 899 1.5 mjl 900 1.8 itojun for (i = infs; *i; i++) { 901 1.5 mjl if (!strcasecmp(s, *i)) 902 1.5 mjl return 1; 903 1.5 mjl } 904 1.5 mjl return 0; 905 1.1 mjl } 906 1.1 mjl 907 1.1 mjl static u_quad_t 908 1.6 ad multiply(u_quad_t n1, u_quad_t n2) 909 1.1 mjl { 910 1.1 mjl static int bpw = 0; 911 1.1 mjl u_quad_t m; 912 1.1 mjl u_quad_t r; 913 1.1 mjl int b1, b2; 914 1.1 mjl 915 1.1 mjl /* 916 1.1 mjl * Get rid of the simple cases 917 1.1 mjl */ 918 1.1 mjl if (n1 == 0 || n2 == 0) 919 1.1 mjl return (0); 920 1.1 mjl if (n1 == 1) 921 1.1 mjl return (n2); 922 1.1 mjl if (n2 == 1) 923 1.1 mjl return (n1); 924 1.1 mjl 925 1.1 mjl /* 926 1.1 mjl * sizeof() returns number of bytes needed for storage. 927 1.1 mjl * This may be different from the actual number of useful bits. 928 1.1 mjl */ 929 1.1 mjl if (!bpw) { 930 1.1 mjl bpw = sizeof(u_quad_t) * 8; 931 1.1 mjl while (((u_quad_t)1 << (bpw-1)) == 0) 932 1.1 mjl --bpw; 933 1.1 mjl } 934 1.1 mjl 935 1.1 mjl /* 936 1.1 mjl * First check the magnitude of each number. If the sum of the 937 1.33 kamil * magnitude is to high, reject the number. (If this test 938 1.1 mjl * is not done then the first multiply below may overflow.) 939 1.1 mjl */ 940 1.1 mjl for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1) 941 1.1 mjl ; 942 1.1 mjl for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2) 943 1.1 mjl ; 944 1.1 mjl if (b1 + b2 - 2 > bpw) { 945 1.1 mjl errno = ERANGE; 946 1.1 mjl return (UQUAD_MAX); 947 1.1 mjl } 948 1.1 mjl 949 1.1 mjl /* 950 1.1 mjl * Decompose the multiplication to be: 951 1.1 mjl * h1 = n1 & ~1 952 1.1 mjl * h2 = n2 & ~1 953 1.1 mjl * l1 = n1 & 1 954 1.1 mjl * l2 = n2 & 1 955 1.1 mjl * (h1 + l1) * (h2 + l2) 956 1.1 mjl * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2) 957 1.1 mjl * 958 1.1 mjl * Since h1 && h2 do not have the low bit set, we can then say: 959 1.1 mjl * 960 1.1 mjl * (h1>>1 * h2>>1 * 4) + ... 961 1.1 mjl * 962 1.1 mjl * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will 963 1.1 mjl * overflow. 964 1.1 mjl * 965 1.1 mjl * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2) 966 1.33 kamil * then adding in residual amount will cause an overflow. 967 1.1 mjl */ 968 1.1 mjl 969 1.1 mjl m = (n1 >> 1) * (n2 >> 1); 970 1.1 mjl 971 1.1 mjl if (m >= ((u_quad_t)1 << (bpw-2))) { 972 1.1 mjl errno = ERANGE; 973 1.1 mjl return (UQUAD_MAX); 974 1.1 mjl } 975 1.1 mjl 976 1.1 mjl m *= 4; 977 1.1 mjl 978 1.1 mjl r = (n1 & n2 & 1) 979 1.1 mjl + (n2 & 1) * (n1 & ~(u_quad_t)1) 980 1.1 mjl + (n1 & 1) * (n2 & ~(u_quad_t)1); 981 1.1 mjl 982 1.1 mjl if ((u_quad_t)(m + r) < m) { 983 1.1 mjl errno = ERANGE; 984 1.1 mjl return (UQUAD_MAX); 985 1.1 mjl } 986 1.1 mjl m += r; 987 1.1 mjl 988 1.1 mjl return (m); 989 1.1 mjl } 990