1 /*- 2 * Copyright (c) 1996 by 3 * Sean Eric Fagan <sef@kithrup.com> 4 * David Nugent <davidn@blaze.net.au> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, is permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice immediately at the beginning of the file, without modification, 12 * this list of conditions, and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. This work was done expressly for inclusion into FreeBSD. Other use 17 * is permitted provided this notation is included. 18 * 4. Absolutely no warranty of function or purpose is made by the authors. 19 * 5. Modifications may be freely made to this file providing the above 20 * conditions are met. 21 * 22 * Low-level routines relating to the user capabilities database 23 * 24 * $FreeBSD$ 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <errno.h> 31 #include <unistd.h> 32 33 #include <sys/types.h> 34 #include <sys/time.h> 35 #include <sys/resource.h> 36 #include <sys/param.h> 37 #include <pwd.h> 38 #include <login_cap.h> 39 40 #ifdef RLIM_LONG 41 # define STRTOV strtol 42 #else 43 # define STRTOV strtoq 44 #endif 45 46 static int lc_object_count = 0; 47 48 static size_t internal_stringsz = 0; 49 static char * internal_string = NULL; 50 static size_t internal_arraysz = 0; 51 static char ** internal_array = NULL; 52 53 static char * 54 allocstr(char * str) 55 { 56 char * p; 57 size_t sz = strlen(str) + 1; /* realloc() only if necessary */ 58 if (sz <= internal_stringsz) 59 p = strcpy(internal_string, str); 60 else if ((p = realloc(internal_string, sz)) != NULL) { 61 internal_stringsz = sz; 62 internal_string = strcpy(p, str); 63 } 64 return p; 65 } 66 67 static char ** 68 allocarray(size_t sz) 69 { 70 char ** p; 71 if (sz <= internal_arraysz) 72 p = internal_array; 73 else if ((p = realloc(internal_array, sz * sizeof(char*))) != NULL) { 74 internal_arraysz = sz; 75 internal_array = p; 76 } 77 return p; 78 } 79 80 81 /* 82 * arrayize() 83 * Turn a simple string <str> seperated by any of 84 * the set of <chars> into an array. The last element 85 * of the array will be NULL, as is proper. 86 * Free using freearraystr() 87 */ 88 89 static char ** 90 arrayize(char *str, const char *chars, int *size) 91 { 92 int i; 93 char *ptr; 94 char **res = NULL; 95 96 for (i = 0, ptr = str; *ptr; i++) { 97 int count = strcspn(ptr, chars); 98 ptr += count; 99 if (*ptr) 100 ++ptr; 101 } 102 103 if ((ptr = allocstr(str)) == NULL) { 104 res = NULL; 105 i = 0; 106 } else if ((res = allocarray(++i)) == NULL) { 107 free(str); 108 i = 0; 109 } else { 110 for (i = 0; *ptr; i++) { 111 int count = strcspn(ptr, chars); 112 res[i] = ptr; 113 ptr += count; 114 if (*ptr) 115 *ptr++ = '\0'; 116 } 117 res[i] = 0; 118 } 119 if (size) 120 *size = i; 121 return res; 122 } 123 124 static void 125 freearraystr(char ** array) 126 { 127 /* 128 * the array[0] should be free'd, and then array. 129 */ 130 if (array) { 131 free(array[0]); 132 free(array); 133 } 134 } 135 136 137 /* 138 * login_close() 139 * Frees up all resources relating to a login class 140 * 141 */ 142 143 void 144 login_close(login_cap_t * lc) 145 { 146 if (lc) { 147 free(lc->lc_style); 148 free(lc->lc_class); 149 free(lc); 150 if (--lc_object_count == 0) { 151 free(internal_string); 152 free(internal_array); 153 internal_array = NULL; 154 internal_string = NULL; 155 cgetclose(); 156 } 157 } 158 } 159 160 161 /* 162 * login_getclassbyname() get the login class by its name. 163 * If the name given is NULL or empty, the default class 164 * LOGIN_DEFCLASS (ie. "default") is fetched. If the 165 * 'dir' argument contains a non-NULL non-empty string, 166 * then the file _FILE_LOGIN_CONF is picked up from that 167 * directory instead of the system login database. 168 * Return a filled-out login_cap_t structure, including 169 * class name, and the capability record buffer. 170 */ 171 172 login_cap_t * 173 login_getclassbyname(char const * name, char const * dir) 174 { 175 login_cap_t *lc = malloc(sizeof(login_cap_t)); 176 177 if (lc != NULL) { 178 int i = 0; 179 char userpath[MAXPATHLEN]; 180 static char *login_dbarray[] = { NULL, NULL, NULL }; 181 182 if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir, _FILE_LOGIN_CONF) < MAXPATHLEN) 183 login_dbarray[i++] = userpath; 184 else 185 login_dbarray[i++] = _PATH_LOGIN_CONF; 186 login_dbarray[i ] = NULL; 187 188 lc->lc_cap = lc->lc_class = lc->lc_style = NULL; 189 190 if ((name == NULL || cgetent(&lc->lc_cap, login_dbarray, (char*)name) != 0) && 191 cgetent(&lc->lc_cap, login_dbarray, (char*)(name = LOGIN_DEFCLASS)) != 0) { 192 free(lc); 193 lc = NULL; 194 } else { 195 ++lc_object_count; 196 lc->lc_class = strdup(name); 197 } 198 } 199 200 return lc; 201 } 202 203 204 205 /* 206 * login_getclass() 207 * Get the login class for a given password entry from 208 * the system (only) login class database. 209 * If the password entry's class field is not set, or 210 * the class specified does not exist, then use the 211 * default of LOGIN_DEFCLASS (ie. "default"). 212 * Return a filled-out login_cap_t structure, including 213 * class name, and the capability record buffer. 214 */ 215 216 login_cap_t * 217 login_getclass(const struct passwd *pwd) 218 { 219 const char * class = NULL; 220 if (pwd != NULL) { 221 if ((class = pwd->pw_class) == NULL || *class == '\0') 222 class = (pwd->pw_uid == 0) ? "root" : NULL; 223 } 224 return login_getclassbyname(class, 0); 225 } 226 227 228 /* 229 * login_getuserclass() 230 * Get the login class for a given password entry, allowing user 231 * overrides via ~/.login_conf. 232 * ### WAS: If the password entry's class field is not set, 233 * ####### or the class specified does not exist, then use 234 * If an entry with the recordid "me" does not exist, then use 235 * the default of LOGIN_DEFCLASS (ie. "default"). 236 * Return a filled-out login_cap_t structure, including 237 * class name, and the capability record buffer. 238 */ 239 240 login_cap_t * 241 login_getuserclass(const struct passwd *pwd) 242 { 243 const char * class = "me"; /* (pwd == NULL) ? NULL : pwd->pw_class; */ 244 const char * home = (pwd == NULL) ? NULL : pwd->pw_dir; 245 return login_getclassbyname(class, home); 246 } 247 248 249 250 /* 251 * login_getcapstr() 252 * Given a login_cap entry, and a capability name, return the 253 * value defined for that capability, a defualt if not found, or 254 * an error string on error. 255 */ 256 257 char * 258 login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error) 259 { 260 char *res; 261 int ret; 262 263 if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0') 264 return def; 265 266 if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) { 267 return def; 268 } else if (ret >= 0) 269 return res; 270 else 271 return error; 272 } 273 274 275 /* 276 * login_getcaplist() 277 * Given a login_cap entry, and a capability name, return the 278 * value defined for that capability split into an array of 279 * strings. 280 */ 281 282 char ** 283 login_getcaplist(login_cap_t *lc, const char * cap, const char * chars) 284 { 285 char * lstring; 286 287 if (chars == NULL) 288 chars = ". \t"; 289 if ((lstring = login_getcapstr(lc, (char*)cap, NULL, NULL)) != NULL) 290 return arrayize(lstring, chars, NULL); 291 return NULL; 292 } 293 294 295 /* 296 * login_getpath() 297 * From the login_cap_t <lc>, get the capability <cap> which is 298 * formatted as either a space or comma delimited list of paths 299 * and append them all into a string and separate by semicolons. 300 * If there is an error of any kind, return <error>. 301 */ 302 303 char * 304 login_getpath(login_cap_t *lc, const char *cap, char * error) 305 { 306 char *str = login_getcapstr(lc, (char*)cap, NULL, NULL); 307 308 if (str == NULL) 309 str = error; 310 else { 311 char *ptr = str; 312 313 while (*ptr) { 314 int count = strcspn(ptr, ", \t"); 315 ptr += count; 316 if (*ptr) 317 *ptr++ = ':'; 318 } 319 } 320 return str; 321 } 322 323 324 /* 325 * login_getcaptime() 326 * From the login_cap_t <lc>, get the capability <cap>, which is 327 * formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not 328 * present in <lc>, return <def>; if there is an error of some kind, 329 * return <error>. 330 */ 331 332 rlim_t 333 login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 334 { 335 char *res, *ep; 336 int ret; 337 rlim_t tot = 0, tim; 338 339 errno = 0; 340 if (lc == NULL || lc->lc_cap == NULL) 341 return def; 342 343 /* 344 * Look for <cap> in lc_cap. 345 * If it's not there (-1), return <def>. 346 * If there's an error, return <error>. 347 */ 348 349 if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) 350 return def; 351 else if (ret < 0) 352 return error; 353 354 /* 355 * "inf" and "infinity" are two special cases for this. 356 */ 357 if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf")) 358 return RLIM_INFINITY; 359 360 /* 361 * Now go through the string, turning something like 1h2m3s into 362 * an integral value. Whee. 363 */ 364 365 errno = 0; 366 while (*res) { 367 tim = STRTOV(res, &ep, 0); 368 if ((ep == NULL) || (ep == res) || errno) { 369 return error; 370 } 371 /* Look for suffixes */ 372 switch (*ep++) { 373 case 0: 374 ep--; break; /* end of string */ 375 case 's': case 'S': /* seconds */ 376 break; 377 case 'm': case 'M': /* minutes */ 378 tim *= 60L; 379 break; 380 case 'h': case 'H': /* hours */ 381 tim *= (60L * 60L); 382 break; 383 case 'd': case 'D': /* days */ 384 tim *= (60L * 60L * 24L); 385 break; 386 case 'w': case 'W': /* weeks */ 387 tim *= (60L * 60L * 24L * 7L); 388 case 'y': case 'Y': /* Years */ 389 /* I refuse to take leap years into account here. Sue me. */ 390 tim *= (60L * 60L * 24L * 365L); 391 default: 392 return error; 393 } 394 res = ep; 395 tot += tim; 396 } 397 return tot; 398 } 399 400 401 /* 402 * login_getcapnum() 403 * From the login_cap_t <lc>, extract the numerical value <cap>. 404 * If it is not present, return <def> for a default, and return 405 * <error> if there is an error. 406 * Like login_getcaptime(), only it only converts to a number, not 407 * to a time; "infinity" and "inf" are 'special.' 408 */ 409 410 rlim_t 411 login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 412 { 413 char *ep, *res; 414 int ret; 415 rlim_t val; 416 417 if (lc == NULL || lc->lc_cap == NULL) 418 return def; 419 420 /* 421 * For BSDI compatibility, try for the tag=<val> first 422 */ 423 if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) { 424 long lval; 425 /* 426 * String capability not present, so try for tag#<val> as numeric 427 */ 428 if ((ret = cgetnum(lc->lc_cap, (char *)cap, &lval)) == -1) 429 return def; /* Not there, so return default */ 430 else if (ret < 0) 431 return error; 432 return (rlim_t)lval; 433 } 434 else if (ret < 0) 435 return error; 436 437 if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf")) 438 return RLIM_INFINITY; 439 440 errno = 0; 441 val = STRTOV(res, &ep, 0); 442 if ((ep == NULL) || (ep == res) || errno) 443 return error; 444 return val; 445 } 446 447 448 /* 449 * login_getcapsize() 450 * From the login_cap_t <lc>, extract the capability <cap>, which is 451 * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity". 452 * If not present, return <def>, or <error> if there is an error of 453 * some sort. 454 */ 455 456 rlim_t 457 login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) { 458 char *ep, *res; 459 int ret; 460 rlim_t val; 461 rlim_t mult; 462 463 if (lc == NULL || lc->lc_cap == NULL) 464 return def; 465 466 if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) 467 return def; 468 else if (ret < 0) 469 return error; 470 471 errno = 0; 472 val = STRTOV(res, &ep, 0); 473 if ((res == NULL) || (res == ep) || errno) 474 return error; 475 switch (*ep) { 476 case 0: /* end of string */ 477 mult = 1; break; 478 case 'b': case 'B': /* 512-byte blocks */ 479 mult = 512; break; 480 case 'k': case 'K': /* 1024-byte Kilobytes */ 481 mult = 1024; break; 482 case 'm': case 'M': /* 1024-k kbytes */ 483 mult = 1024 * 1024; break; 484 case 'g': case 'G': /* 1Gbyte */ 485 mult = 1024 * 1024 * 1024; break; 486 #ifndef RLIM_LONG 487 case 't': case 'T': /* 1TBte */ 488 mult = 1024LL * 1024LL * 1024LL * 1024LL; break; 489 #endif 490 default: 491 return error; 492 } 493 return val * mult; 494 } 495 496 497 /* 498 * login_getcapbool() 499 * From the login_cap_t <lc>, check for the existance of the capability 500 * of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return 501 * the whether or not <cap> exists there. 502 */ 503 504 int 505 login_getcapbool(login_cap_t *lc, const char *cap, int def) 506 { 507 if (lc == NULL || lc->lc_cap == NULL) 508 return def; 509 return (cgetcap(lc->lc_cap, (char *)cap, ':') != NULL); 510 } 511 512 513 /* 514 * login_getstyle() 515 * Given a login_cap entry <lc>, and optionally a type of auth <auth>, 516 * and optionally a style <style>, find the style that best suits these 517 * rules: 518 * 1. If <auth> is non-null, look for an "auth-<auth>=" string 519 * in the capability; if not present, default to "auth=". 520 * 2. If there is no auth list found from (1), default to 521 * "passwd" as an authorization list. 522 * 3. If <style> is non-null, look for <style> in the list of 523 * authorization methods found from (2); if <style> is NULL, default 524 * to LOGIN_DEFSTYLE ("passwd"). 525 * 4. If the chosen style is found in the chosen list of authorization 526 * methods, return that; otherwise, return NULL. 527 * E.g.: 528 * login_getstyle(lc, NULL, "ftp"); 529 * login_getstyle(lc, "login", NULL); 530 * login_getstyle(lc, "skey", "network"); 531 */ 532 533 char * 534 login_getstyle(login_cap_t *lc, char *style, const char *auth) 535 { 536 int i; 537 char **authtypes = NULL; 538 char *auths= NULL; 539 char realauth[64]; 540 541 static char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL }; 542 543 if (auth != NULL && *auth != '\0' && 544 snprintf(realauth, sizeof realauth, "auth-%s", auth) < sizeof realauth) 545 authtypes = login_getcaplist(lc, realauth, NULL); 546 547 if (authtypes == NULL) 548 authtypes = login_getcaplist(lc, "auth", NULL); 549 550 if (authtypes == NULL) 551 authtypes = defauthtypes; 552 553 /* 554 * We have at least one authtype now; auths is a comma-seperated 555 * (or space-separated) list of authentication types. We have to 556 * convert from this to an array of char*'s; authtypes then gets this. 557 */ 558 i = 0; 559 if (style != NULL && *style != '\0') { 560 while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0) 561 i++; 562 } 563 lc->lc_style = NULL; 564 if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL) 565 lc->lc_style = auths; 566 567 return lc->lc_style; 568 } 569 570 571