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 * Portions copyright (c) 1995,1997 8 * Berkeley Software Design, Inc. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, is permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice immediately at the beginning of the file, without modification, 16 * this list of conditions, and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. This work was done expressly for inclusion into FreeBSD. Other use 21 * is permitted provided this notation is included. 22 * 4. Absolutely no warranty of function or purpose is made by the authors. 23 * 5. Modifications may be freely made to this file providing the above 24 * conditions are met. 25 * 26 * Low-level routines relating to the user capabilities database 27 * 28 * $FreeBSD: head/lib/libutil/login_cap.c 255007 2013-08-28 21:10:37Z jilles $ 29 */ 30 31 #include <sys/types.h> 32 #include <sys/time.h> 33 #include <sys/resource.h> 34 #include <sys/param.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <libutil.h> 38 #include <login_cap.h> 39 #include <pwd.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <syslog.h> 44 #include <unistd.h> 45 46 /* 47 * allocstr() 48 * Manage a single static pointer for handling a local char* buffer, 49 * resizing as necessary to contain the string. 50 * 51 * allocarray() 52 * Manage a static array for handling a group of strings, resizing 53 * when necessary. 54 */ 55 56 static int lc_object_count = 0; 57 58 static size_t internal_stringsz = 0; 59 static char * internal_string = NULL; 60 static size_t internal_arraysz = 0; 61 static const char ** internal_array = NULL; 62 63 static char path_login_conf[] = _PATH_LOGIN_CONF; 64 65 static char * 66 allocstr(const char *str) 67 { 68 char *p; 69 70 size_t sz = strlen(str) + 1; /* realloc() only if necessary */ 71 if (sz <= internal_stringsz) 72 p = strcpy(internal_string, str); 73 else if ((p = realloc(internal_string, sz)) != NULL) { 74 internal_stringsz = sz; 75 internal_string = strcpy(p, str); 76 } 77 return p; 78 } 79 80 81 static const char ** 82 allocarray(size_t sz) 83 { 84 static const char **p; 85 86 if (sz <= internal_arraysz) 87 p = internal_array; 88 else if ((p = realloc(internal_array, sz * sizeof(char*))) != NULL) { 89 internal_arraysz = sz; 90 internal_array = p; 91 } 92 return p; 93 } 94 95 96 /* 97 * arrayize() 98 * Turn a simple string <str> separated by any of 99 * the set of <chars> into an array. The last element 100 * of the array will be NULL, as is proper. 101 * Free using freearraystr() 102 */ 103 104 static const char ** 105 arrayize(const char *str, const char *chars, int *size) 106 { 107 int i; 108 char *ptr; 109 const char *cptr; 110 const char **res = NULL; 111 112 /* count the sub-strings */ 113 for (i = 0, cptr = str; *cptr; i++) { 114 int count = strcspn(cptr, chars); 115 cptr += count; 116 if (*cptr) 117 ++cptr; 118 } 119 120 /* alloc the array */ 121 if ((ptr = allocstr(str)) != NULL) { 122 if ((res = allocarray(++i)) == NULL) 123 free((void *)(uintptr_t)(const void *)str); 124 else { 125 /* now split the string */ 126 i = 0; 127 while (*ptr) { 128 int count = strcspn(ptr, chars); 129 res[i++] = ptr; 130 ptr += count; 131 if (*ptr) 132 *ptr++ = '\0'; 133 } 134 res[i] = NULL; 135 } 136 } 137 138 if (size) 139 *size = i; 140 141 return res; 142 } 143 144 145 /* 146 * login_close() 147 * Frees up all resources relating to a login class 148 * 149 */ 150 151 void 152 login_close(login_cap_t * lc) 153 { 154 if (lc) { 155 free(lc->lc_style); 156 free(lc->lc_class); 157 free(lc->lc_cap); 158 free(lc); 159 if (--lc_object_count == 0) { 160 free(internal_string); 161 free(internal_array); 162 internal_array = NULL; 163 internal_arraysz = 0; 164 internal_string = NULL; 165 internal_stringsz = 0; 166 cgetclose(); 167 } 168 } 169 } 170 171 172 /* 173 * login_getclassbyname() 174 * Get the login class by its name. 175 * If the name given is NULL or empty, the default class 176 * LOGIN_DEFCLASS (i.e., "default") is fetched. 177 * If the name given is LOGIN_MECLASS and 178 * 'pwd' argument is non-NULL and contains an non-NULL 179 * dir entry, then the file _FILE_LOGIN_CONF is picked 180 * up from that directory and used before the system 181 * login database. In that case the system login database 182 * is looked up using LOGIN_MECLASS, too, which is a bug. 183 * Return a filled-out login_cap_t structure, including 184 * class name, and the capability record buffer. 185 */ 186 187 login_cap_t * 188 login_getclassbyname(char const *name, const struct passwd *pwd) 189 { 190 login_cap_t *lc; 191 192 if ((lc = malloc(sizeof(login_cap_t))) != NULL) { 193 int r, me, i = 0; 194 uid_t euid = 0; 195 gid_t egid = 0; 196 const char *msg = NULL; 197 const char *dir; 198 char userpath[MAXPATHLEN]; 199 200 static char *login_dbarray[] = { NULL, NULL, NULL }; 201 202 me = (name != NULL && strcmp(name, LOGIN_MECLASS) == 0); 203 dir = (!me || pwd == NULL) ? NULL : pwd->pw_dir; 204 /* 205 * Switch to user mode before checking/reading its ~/.login_conf 206 * - some NFSes have root read access disabled. 207 * 208 * XXX: This fails to configure additional groups. 209 */ 210 if (dir) { 211 euid = geteuid(); 212 egid = getegid(); 213 (void)setegid(pwd->pw_gid); 214 (void)seteuid(pwd->pw_uid); 215 } 216 217 if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir, 218 _FILE_LOGIN_CONF) < MAXPATHLEN) { 219 if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1) 220 login_dbarray[i++] = userpath; 221 } 222 /* 223 * XXX: Why to add the system database if the class is `me'? 224 */ 225 if (_secure_path(path_login_conf, 0, 0) != -1) 226 login_dbarray[i++] = path_login_conf; 227 login_dbarray[i] = NULL; 228 229 memset(lc, 0, sizeof(login_cap_t)); 230 lc->lc_cap = lc->lc_class = lc->lc_style = NULL; 231 232 if (name == NULL || *name == '\0') 233 name = LOGIN_DEFCLASS; 234 235 switch (cgetent(&lc->lc_cap, login_dbarray, name)) { 236 case -1: /* Failed, entry does not exist */ 237 if (me) 238 break; /* Don't retry default on 'me' */ 239 if (i == 0) 240 r = -1; 241 else if ((r = open(login_dbarray[0], O_RDONLY | O_CLOEXEC)) >= 0) 242 close(r); 243 /* 244 * If there's at least one login class database, 245 * and we aren't searching for a default class 246 * then complain about a non-existent class. 247 */ 248 if (r >= 0 || strcmp(name, LOGIN_DEFCLASS) != 0) 249 syslog(LOG_ERR, "login_getclass: unknown class '%s'", name); 250 /* fall-back to default class */ 251 name = LOGIN_DEFCLASS; 252 msg = "%s: no default/fallback class '%s'"; 253 if (cgetent(&lc->lc_cap, login_dbarray, name) != 0 && r >= 0) 254 break; 255 /* FALLTHROUGH - just return system defaults */ 256 case 0: /* success! */ 257 if ((lc->lc_class = strdup(name)) != NULL) { 258 if (dir) { 259 (void)seteuid(euid); 260 (void)setegid(egid); 261 } 262 ++lc_object_count; 263 return lc; 264 } 265 msg = "%s: strdup: %m"; 266 break; 267 case -2: 268 msg = "%s: retrieving class information: %m"; 269 break; 270 case -3: 271 msg = "%s: 'tc=' reference loop '%s'"; 272 break; 273 case 1: 274 msg = "couldn't resolve 'tc=' reference in '%s'"; 275 break; 276 default: 277 msg = "%s: unexpected cgetent() error '%s': %m"; 278 break; 279 } 280 if (dir) { 281 (void)seteuid(euid); 282 (void)setegid(egid); 283 } 284 if (msg != NULL) 285 syslog(LOG_ERR, msg, "login_getclass", name); 286 free(lc); 287 } 288 289 return NULL; 290 } 291 292 293 294 /* 295 * login_getclass() 296 * Get the login class for the system (only) login class database. 297 * Return a filled-out login_cap_t structure, including 298 * class name, and the capability record buffer. 299 */ 300 301 login_cap_t * 302 login_getclass(const char *cls) 303 { 304 return login_getclassbyname(cls, NULL); 305 } 306 307 308 /* 309 * login_getpwclass() 310 * Get the login class for a given password entry from 311 * the system (only) login class database. 312 * If the password entry's class field is not set, or 313 * the class specified does not exist, then use the 314 * default of LOGIN_DEFCLASS (i.e., "default") for an unprivileged 315 * user or that of LOGIN_DEFROOTCLASS (i.e., "root") for a super-user. 316 * Return a filled-out login_cap_t structure, including 317 * class name, and the capability record buffer. 318 */ 319 320 login_cap_t * 321 login_getpwclass(const struct passwd *pwd) 322 { 323 const char *cls = NULL; 324 325 if (pwd != NULL) { 326 cls = pwd->pw_class; 327 if (cls == NULL || *cls == '\0') 328 cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; 329 } 330 /* 331 * XXX: pwd should be unused by login_getclassbyname() unless cls is `me', 332 * so NULL can be passed instead of pwd for more safety. 333 */ 334 return login_getclassbyname(cls, pwd); 335 } 336 337 338 /* 339 * login_getuserclass() 340 * Get the `me' login class, allowing user overrides via ~/.login_conf. 341 * Note that user overrides are allowed only in the `me' class. 342 */ 343 344 login_cap_t * 345 login_getuserclass(const struct passwd *pwd) 346 { 347 return login_getclassbyname(LOGIN_MECLASS, pwd); 348 } 349 350 351 /* 352 * login_getcapstr() 353 * Given a login_cap entry, and a capability name, return the 354 * value defined for that capability, a default if not found, or 355 * an error string on error. 356 */ 357 358 const char * 359 login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const char *error) 360 { 361 char *res; 362 int ret; 363 364 if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0') 365 return def; 366 367 if ((ret = cgetstr(lc->lc_cap, cap, &res)) == -1) 368 return def; 369 return (ret >= 0) ? res : error; 370 } 371 372 373 /* 374 * login_getcaplist() 375 * Given a login_cap entry, and a capability name, return the 376 * value defined for that capability split into an array of 377 * strings. 378 */ 379 380 const char ** 381 login_getcaplist(login_cap_t *lc, const char *cap, const char *chars) 382 { 383 const char *lstring; 384 385 if (chars == NULL) 386 chars = ", \t"; 387 if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL) 388 return arrayize(lstring, chars, NULL); 389 return NULL; 390 } 391 392 393 /* 394 * login_getpath() 395 * From the login_cap_t <lc>, get the capability <cap> which is 396 * formatted as either a space or comma delimited list of paths 397 * and append them all into a string and separate by semicolons. 398 * If there is an error of any kind, return <error>. 399 */ 400 401 const char * 402 login_getpath(login_cap_t *lc, const char *cap, const char *error) 403 { 404 const char *str; 405 char *ptr; 406 int count; 407 408 str = login_getcapstr(lc, cap, NULL, NULL); 409 if (str == NULL) 410 return error; 411 ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */ 412 while (*ptr) { 413 count = strcspn(ptr, ", \t"); 414 ptr += count; 415 if (*ptr) 416 *ptr++ = ':'; 417 } 418 return str; 419 } 420 421 422 static int 423 isinfinite(const char *s) 424 { 425 static const char *infs[] = { 426 "infinity", 427 "inf", 428 "unlimited", 429 "unlimit", 430 "-1", 431 NULL 432 }; 433 const char **i = &infs[0]; 434 435 while (*i != NULL) { 436 if (strcasecmp(s, *i) == 0) 437 return 1; 438 ++i; 439 } 440 return 0; 441 } 442 443 444 static u_quad_t 445 rmultiply(u_quad_t n1, u_quad_t n2) 446 { 447 u_quad_t m, r; 448 int b1, b2; 449 450 static int bpw = 0; 451 452 /* Handle simple cases */ 453 if (n1 == 0 || n2 == 0) 454 return 0; 455 if (n1 == 1) 456 return n2; 457 if (n2 == 1) 458 return n1; 459 460 /* 461 * sizeof() returns number of bytes needed for storage. 462 * This may be different from the actual number of useful bits. 463 */ 464 if (!bpw) { 465 bpw = sizeof(u_quad_t) * 8; 466 while (((u_quad_t)1 << (bpw-1)) == 0) 467 --bpw; 468 } 469 470 /* 471 * First check the magnitude of each number. If the sum of the 472 * magnatude is way to high, reject the number. (If this test 473 * is not done then the first multiply below may overflow.) 474 */ 475 for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1) 476 ; 477 for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2) 478 ; 479 if (b1 + b2 - 2 > bpw) { 480 errno = ERANGE; 481 return (UQUAD_MAX); 482 } 483 484 /* 485 * Decompose the multiplication to be: 486 * h1 = n1 & ~1 487 * h2 = n2 & ~1 488 * l1 = n1 & 1 489 * l2 = n2 & 1 490 * (h1 + l1) * (h2 + l2) 491 * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2) 492 * 493 * Since h1 && h2 do not have the low bit set, we can then say: 494 * 495 * (h1>>1 * h2>>1 * 4) + ... 496 * 497 * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will 498 * overflow. 499 * 500 * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2) 501 * then adding in residual amout will cause an overflow. 502 */ 503 504 m = (n1 >> 1) * (n2 >> 1); 505 if (m >= ((u_quad_t)1 << (bpw-2))) { 506 errno = ERANGE; 507 return (UQUAD_MAX); 508 } 509 m *= 4; 510 511 r = (n1 & n2 & 1) 512 + (n2 & 1) * (n1 & ~(u_quad_t)1) 513 + (n1 & 1) * (n2 & ~(u_quad_t)1); 514 515 if ((u_quad_t)(m + r) < m) { 516 errno = ERANGE; 517 return (UQUAD_MAX); 518 } 519 m += r; 520 521 return (m); 522 } 523 524 525 /* 526 * login_getcaptime() 527 * From the login_cap_t <lc>, get the capability <cap>, which is 528 * formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not 529 * present in <lc>, return <def>; if there is an error of some kind, 530 * return <error>. 531 */ 532 533 rlim_t 534 login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 535 { 536 char *res, *ep, *oval; 537 int r; 538 rlim_t tot; 539 540 errno = 0; 541 if (lc == NULL || lc->lc_cap == NULL) 542 return def; 543 544 /* 545 * Look for <cap> in lc_cap. 546 * If it's not there (-1), return <def>. 547 * If there's an error, return <error>. 548 */ 549 550 if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) 551 return def; 552 else if (r < 0) { 553 errno = ERANGE; 554 return error; 555 } 556 557 /* "inf" and "infinity" are special cases */ 558 if (isinfinite(res)) 559 return RLIM_INFINITY; 560 561 /* 562 * Now go through the string, turning something like 1h2m3s into 563 * an integral value. Whee. 564 */ 565 566 errno = 0; 567 tot = 0; 568 oval = res; 569 while (*res) { 570 rlim_t tim = strtoq(res, &ep, 0); 571 rlim_t mult = 1; 572 573 if (ep == NULL || ep == res || errno != 0) { 574 invalid: 575 syslog(LOG_WARNING, "login_getcaptime: class '%s' bad value %s=%s", 576 lc->lc_class, cap, oval); 577 errno = ERANGE; 578 return error; 579 } 580 /* Look for suffixes */ 581 switch (*ep++) { 582 case 0: 583 ep--; 584 break; /* end of string */ 585 case 's': case 'S': /* seconds */ 586 break; 587 case 'm': case 'M': /* minutes */ 588 mult = 60; 589 break; 590 case 'h': case 'H': /* hours */ 591 mult = 60L * 60L; 592 break; 593 case 'd': case 'D': /* days */ 594 mult = 60L * 60L * 24L; 595 break; 596 case 'w': case 'W': /* weeks */ 597 mult = 60L * 60L * 24L * 7L; 598 break; 599 case 'y': case 'Y': /* 365-day years */ 600 mult = 60L * 60L * 24L * 365L; 601 break; 602 default: 603 goto invalid; 604 } 605 res = ep; 606 tot += rmultiply(tim, mult); 607 if (errno) 608 goto invalid; 609 } 610 611 return tot; 612 } 613 614 615 /* 616 * login_getcapnum() 617 * From the login_cap_t <lc>, extract the numerical value <cap>. 618 * If it is not present, return <def> for a default, and return 619 * <error> if there is an error. 620 * Like login_getcaptime(), only it only converts to a number, not 621 * to a time; "infinity" and "inf" are 'special.' 622 */ 623 624 rlim_t 625 login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 626 { 627 char *ep, *res; 628 int r; 629 rlim_t val; 630 631 if (lc == NULL || lc->lc_cap == NULL) 632 return def; 633 634 /* 635 * For BSDI compatibility, try for the tag=<val> first 636 */ 637 if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) { 638 long lval; 639 /* string capability not present, so try for tag#<val> as numeric */ 640 if ((r = cgetnum(lc->lc_cap, cap, &lval)) == -1) 641 return def; /* Not there, so return default */ 642 else if (r >= 0) 643 return (rlim_t)lval; 644 } 645 646 if (r < 0) { 647 errno = ERANGE; 648 return error; 649 } 650 651 if (isinfinite(res)) 652 return RLIM_INFINITY; 653 654 errno = 0; 655 val = strtoq(res, &ep, 0); 656 if (ep == NULL || ep == res || errno != 0) { 657 syslog(LOG_WARNING, "login_getcapnum: class '%s' bad value %s=%s", 658 lc->lc_class, cap, res); 659 errno = ERANGE; 660 return error; 661 } 662 663 return val; 664 } 665 666 667 668 /* 669 * login_getcapsize() 670 * From the login_cap_t <lc>, extract the capability <cap>, which is 671 * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity". 672 * If not present, return <def>, or <error> if there is an error of 673 * some sort. 674 */ 675 676 rlim_t 677 login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 678 { 679 char *ep, *res, *oval; 680 int r; 681 rlim_t tot; 682 683 if (lc == NULL || lc->lc_cap == NULL) 684 return def; 685 686 if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) 687 return def; 688 else if (r < 0) { 689 errno = ERANGE; 690 return error; 691 } 692 693 if (isinfinite(res)) 694 return RLIM_INFINITY; 695 696 errno = 0; 697 tot = 0; 698 oval = res; 699 while (*res) { 700 rlim_t siz = strtoq(res, &ep, 0); 701 rlim_t mult = 1; 702 703 if (ep == NULL || ep == res || errno != 0) { 704 invalid: 705 syslog(LOG_WARNING, "login_getcapsize: class '%s' bad value %s=%s", 706 lc->lc_class, cap, oval); 707 errno = ERANGE; 708 return error; 709 } 710 switch (*ep++) { 711 case 0: /* end of string */ 712 ep--; 713 break; 714 case 'b': case 'B': /* 512-byte blocks */ 715 mult = 512; 716 break; 717 case 'k': case 'K': /* 1024-byte Kilobytes */ 718 mult = 1024; 719 break; 720 case 'm': case 'M': /* 1024-k kbytes */ 721 mult = 1024 * 1024; 722 break; 723 case 'g': case 'G': /* 1Gbyte */ 724 mult = 1024 * 1024 * 1024; 725 break; 726 case 't': case 'T': /* 1TBte */ 727 mult = 1024LL * 1024LL * 1024LL * 1024LL; 728 break; 729 default: 730 goto invalid; 731 } 732 res = ep; 733 tot += rmultiply(siz, mult); 734 if (errno) 735 goto invalid; 736 } 737 738 return tot; 739 } 740 741 742 /* 743 * login_getcapbool() 744 * From the login_cap_t <lc>, check for the existance of the capability 745 * of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return 746 * the whether or not <cap> exists there. 747 */ 748 749 int 750 login_getcapbool(login_cap_t *lc, const char *cap, int def) 751 { 752 if (lc == NULL || lc->lc_cap == NULL) 753 return def; 754 return (cgetcap(lc->lc_cap, cap, ':') != NULL); 755 } 756 757 758 /* 759 * login_getstyle() 760 * Given a login_cap entry <lc>, and optionally a type of auth <auth>, 761 * and optionally a style <style>, find the style that best suits these 762 * rules: 763 * 1. If <auth> is non-null, look for an "auth-<auth>=" string 764 * in the capability; if not present, default to "auth=". 765 * 2. If there is no auth list found from (1), default to 766 * "passwd" as an authorization list. 767 * 3. If <style> is non-null, look for <style> in the list of 768 * authorization methods found from (2); if <style> is NULL, default 769 * to LOGIN_DEFSTYLE ("passwd"). 770 * 4. If the chosen style is found in the chosen list of authorization 771 * methods, return that; otherwise, return NULL. 772 * E.g.: 773 * login_getstyle(lc, NULL, "ftp"); 774 * login_getstyle(lc, "login", NULL); 775 * login_getstyle(lc, "skey", "network"); 776 */ 777 778 const char * 779 login_getstyle(login_cap_t *lc, const char *style, const char *auth) 780 { 781 int i; 782 const char **authtypes = NULL; 783 char *auths= NULL; 784 char realauth[64]; 785 786 static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL }; 787 788 if (auth != NULL && *auth != '\0') { 789 if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)sizeof(realauth)) 790 authtypes = login_getcaplist(lc, realauth, NULL); 791 } 792 793 if (authtypes == NULL) 794 authtypes = login_getcaplist(lc, "auth", NULL); 795 796 if (authtypes == NULL) 797 authtypes = defauthtypes; 798 799 /* 800 * We have at least one authtype now; auths is a comma-separated 801 * (or space-separated) list of authentication types. We have to 802 * convert from this to an array of char*'s; authtypes then gets this. 803 */ 804 i = 0; 805 if (style != NULL && *style != '\0') { 806 while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0) 807 i++; 808 } 809 810 lc->lc_style = NULL; 811 if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL) 812 lc->lc_style = auths; 813 814 if (lc->lc_style != NULL) 815 lc->lc_style = strdup(lc->lc_style); 816 817 return lc->lc_style; 818 } 819