1 #include <sys/types.h>
   2 #include <sys/stat.h>
   3 #include <fcntl.h>
   4 #include <stdio.h>
   5 #include <stdlib.h>
   6 #include <string.h>
   7 #include <errno.h>
   8 #include <locale.h>
   9 #include <stddef.h>
  10 #include <limits.h>
  11 #include <pwd.h>
  12 #include <grp.h>
  13 #include <unistd.h>
  14 #include <rctl.h>
  15 #include <regex.h>
  16 #include <ctype.h>
  17 
  18 #include "projent.h"
  19 #include "attrib.h"
  20 #include "util.h"
  21 
  22 
  23 #define BOSTR_REG_EXP   "^"
  24 #define EOSTR_REG_EXP   "$"
  25 #define IDENT_REG_EXP   "[[:alpha:]][[:alnum:]_.-]*"
  26 #define PRJID_REG_EXP   "[[:digit:]]+"
  27 #define USERN_REG_EXP   "!?[[:alpha:]][[:alnum:]_.-]*"
  28 #define GRUPN_REG_EXP   "!?[[:alnum:]][[:alnum:]]*"
  29 
  30 #define TO_EXP(X)       BOSTR_REG_EXP X EOSTR_REG_EXP
  31 
  32 #define PROJN_EXP       TO_EXP(IDENT_REG_EXP)
  33 #define PRJID_EXP       TO_EXP(PRJID_REG_EXP)
  34 #define USERN_EXP       TO_EXP(USERN_REG_EXP)
  35 #define GRUPN_EXP       TO_EXP(GRUPN_REG_EXP)
  36 
  37 /*ARGSUSED*/
  38 int
  39 projent_validate_name(char *pname, lst_t *errlst)
  40 {
  41         /* Do nothing, as any parse-able project name is valid */
  42         return (0);
  43 }
  44 
  45 /*ARGSUSED*/
  46 int
  47 projent_validate_comment(char *comment, lst_t *errlst)
  48 {
  49         /* Do nothing, as any parse-able project name is valid */
  50         return (0);
  51 }
  52 
  53 int
  54 projent_validate_users(char *users, lst_t *errlst)
  55 {
  56         char *susrs, *usrs, *usr;
  57         char *u, **ulast, **ulist;
  58         int ret = 0;
  59         int i;
  60 
  61         susrs = usrs = util_safe_strdup(users);
  62         ulast = ulist = util_safe_zmalloc(
  63             (strlen(users) + 1) * sizeof (char *));
  64         while ((usr = strsep(&usrs, ",")) != NULL) {
  65                 if (*usr == '!')
  66                         usr++;
  67                 if ((*usr == '\0') || (strcmp(usr, "*") == 0))
  68                         continue;
  69 
  70                 if (getpwnam(usr) == NULL) {
  71                         util_add_errmsg(errlst, gettext(
  72                             "User \"%s\" does not exist"), usr);
  73                         ret = 1;
  74                 }
  75                 for (i = 0; (u = ulist[i]) != NULL; i++) {
  76                         if (strcmp(u, usr) == 0) {
  77                                 util_add_errmsg(errlst, gettext(
  78                                     "Duplicate user names \"%s\""), usr);
  79                                 ret = 1;
  80                         }
  81                 }
  82                 /* Add the user to the temporary list if not found */
  83                 if (u == NULL) {
  84                         *ulast++ = usr;
  85                 }
  86         }
  87         free(ulist);
  88         free(susrs);
  89         return (ret);
  90 }
  91 
  92 int
  93 projent_validate_groups(char *groups, lst_t *errlst)
  94 {
  95         char *sgrps, *grps, *grp;
  96         char *g, **glast, **glist;
  97         int ret = 0;
  98         int i;
  99 
 100         sgrps = grps = util_safe_strdup(groups);
 101         glast = glist = util_safe_zmalloc(
 102             (strlen(groups) + 1) * sizeof (char *));
 103         while ((grp = strsep(&grps, ",")) != NULL) {
 104                 if (*grp == '!')
 105                         grp++;
 106                 if ((*grp == '\0') || (strcmp(grp, "*") == 0))
 107                         continue;
 108 
 109                 if (getgrnam(grp) == NULL) {
 110                         util_add_errmsg(errlst, gettext(
 111                             "Group \"%s\" does not exist"), grp);
 112                         ret = 1;
 113                 }
 114                 for (i = 0; (g = glist[i]) != NULL; i++) {
 115                         if (strcmp(g, grp) == 0) {
 116                                 util_add_errmsg(errlst, gettext(
 117                                     "Duplicate group names \"%s\""), grp);
 118                                 ret = 1;
 119                         }
 120                 }
 121                 /* Add the group to the temporary list if not found */
 122                 if (g == NULL) {
 123                         *glast++ = grp;
 124                 }
 125         }
 126         free(glist);
 127         free(sgrps);
 128         return (ret);
 129 }
 130 
 131 int
 132 projent_validate_attributes(lst_t *attrs, lst_t *errlst)
 133 {
 134         return (attrib_validate_lst(attrs, errlst));
 135 }
 136 
 137 char *
 138 projent_tostring(projent_t *ent)
 139 {
 140         char *attrs;
 141         char *ret = NULL;
 142         if ((attrs = attrib_lst_tostring(ent->attrs)) != NULL) {
 143                 (void) asprintf(&ret, "%s:%ld:%s:%s:%s:%s",
 144                     ent->projname,
 145                     ent->projid,
 146                     ent->comment,
 147                     ent->userlist,
 148                     ent->grouplist,
 149                     attrs);
 150                 free(attrs);
 151         }
 152         return (ret);
 153 }
 154 
 155 int
 156 projent_validate(projent_t *pent, int flags, lst_t *errlst)
 157 {
 158         char *str;
 159 
 160         (void) projent_validate_name(pent->projname, errlst);
 161         (void) projent_validate_projid(pent->projid, flags, errlst);
 162         (void) projent_validate_comment(pent->comment, errlst);
 163         (void) projent_validate_users(pent->userlist, errlst);
 164         (void) projent_validate_groups(pent->grouplist, errlst);
 165         (void) projent_validate_attributes(pent->attrs, errlst);
 166 
 167         if ((str = projent_tostring(pent)) == NULL) {
 168                 util_add_errmsg(errlst, gettext("error allocating memory"));
 169         } else {
 170                 if (strlen(str) > (PROJECT_BUFSZ - 2)) {
 171                         util_add_errmsg(errlst, gettext(
 172                             "projent line too long"));
 173                 }
 174                 free(str);
 175         }
 176         return (lst_is_empty(errlst) == 0);
 177 }
 178 
 179 int
 180 projent_validate_lst(lst_t *plst, int flags, lst_t *errlst)
 181 {
 182         int e, i, idx;
 183         projent_t *ent;
 184         char *pnames = NULL;
 185         projid_t *pids = NULL;
 186         int ret = 0;
 187 
 188         idx = 0;
 189         for (e = 0; e < lst_size(plst); e++) {
 190                 ent = lst_at(plst, e);
 191                 /* Check for duplicate projname */
 192                 if (pnames != NULL && strstr(pnames, ent->projname) != NULL) {
 193                         util_add_errmsg(errlst, gettext(
 194                             "Duplicate project name %s"), ent->projname);
 195                         ret++;
 196                 }
 197 
 198                 /* Check for duplicate projid if DUP is not allowed */
 199                 if (!(flags & F_PAR_DUP) && pids != NULL) {
 200                         for (i = 0; i < idx; i++) {
 201                                 if (ent->projid == pids[i]) {
 202                                         util_add_errmsg(errlst, gettext(
 203                                             "Duplicate proid %d"), ent->projid);
 204                                         ret++;
 205                                         break;
 206                                 }
 207                         }
 208                 }
 209 
 210                 /* Add the projname an projid to out temp list */
 211                 pnames = UTIL_STR_APPEND2(pnames, "|", ent->projname);
 212                 pids = util_safe_realloc(pids, (idx + 1) * sizeof (projid_t));
 213                 pids[idx] = ent->projid;
 214                 idx++;
 215 
 216                 /* Validate the projet */
 217                 ret += projent_validate(ent, flags, errlst);
 218         }
 219 
 220         free(pnames);
 221         free(pids);
 222 
 223         return (ret);
 224 }
 225 
 226 void
 227 projent_free_attributes(lst_t *attribs)
 228 {
 229         attrib_free_lst(attribs);
 230 }
 231 
 232 void
 233 projent_sort_attributes(lst_t *attribs)
 234 {
 235         attrib_sort_lst(attribs);
 236 }
 237 
 238 char *
 239 projent_attrib_tostring(void *attrib)
 240 {
 241         return (attrib_tostring(attrib));
 242 }
 243 
 244 char *
 245 projent_attrib_lst_tostring(lst_t *lst)
 246 {
 247         return (attrib_lst_tostring(lst));
 248 }
 249 
 250 void
 251 projent_merge_attributes(lst_t **eattrs, lst_t *nattrs, int flags,
 252     lst_t *errlst)
 253 {
 254         attrib_merge_attrib_lst(eattrs, nattrs, flags, errlst);
 255 }
 256 
 257 lst_t *
 258 projent_parse_attributes(char *attribs, int flags, lst_t *errlst)
 259 {
 260         return (attrib_parse_attributes(attribs, flags, errlst));
 261 }
 262 
 263 void
 264 projent_merge_usrgrp(char *usrgrp, char **elist, char *nlist,
 265     int flags, lst_t *errlst)
 266 {
 267         char *res = NULL;
 268         char *seusrs, *eusrs, *eusr;
 269         char *snusrs, *nusrs, *nusr;
 270         char *sn1usrs, *n1usrs, *n1usr;
 271         char *sep;
 272         int i, j;
 273 
 274         sep = (flags & F_PAR_SPC) ? " ," : ",";
 275 
 276         if (flags & F_MOD_ADD) {
 277                 res = util_safe_strdup(*elist);
 278 
 279                 snusrs = nusrs = util_safe_strdup(nlist);
 280                 while ((nusr = strsep(&nusrs, sep)) != NULL) {
 281                         if (*nusr == '\0')
 282                                 continue;
 283                         seusrs = eusrs = util_safe_strdup(*elist);
 284                         while ((eusr = strsep(&eusrs, sep)) != NULL) {
 285                                 if (*eusr == '\0')
 286                                         continue;
 287                                 if (strcmp(eusr, nusr) == 0) {
 288                                         util_add_errmsg(errlst, gettext(
 289                                             "Project already contains"
 290                                             " %s \"%s\""), usrgrp, nusr);
 291                                         UTIL_FREE_SNULL(res);
 292                                         free(seusrs);
 293                                         free(snusrs);
 294                                         goto out;
 295                                 }
 296                         }
 297                         free(seusrs);
 298                         /* Append nusr to the result */
 299                         if (*res != '\0')
 300                                 res = UTIL_STR_APPEND1(res, ",");
 301                         res = UTIL_STR_APPEND1(res, nusr);
 302                 }
 303                 free(snusrs);
 304         } else if (flags & F_MOD_REM) {
 305 
 306                 snusrs = nusrs = util_safe_strdup(nlist);
 307                 for (i = 0; (nusr = strsep(&nusrs, sep)) != NULL; i++) {
 308                         if (*nusr == '\0')
 309                                 continue;
 310                         sn1usrs = n1usrs = util_safe_strdup(nlist);
 311                         for (j = 0; (n1usr = strsep(&n1usrs, sep)) != NULL;
 312                             j++) {
 313                                 if (i != j && strcmp(nusr, n1usr) == 0) {
 314                                         util_add_errmsg(errlst, gettext(
 315                                             "Duplicate %s name \"%s\""),
 316                                             usrgrp, nusr);
 317                                         free(sn1usrs);
 318                                         free(snusrs);
 319                                         goto out;
 320                                 }
 321                         }
 322                         free(sn1usrs);
 323 
 324                         seusrs = eusrs = util_safe_strdup(*elist);
 325                         while ((eusr = strsep(&eusrs, sep)) != NULL) {
 326                                 if (strcmp(nusr, eusr) == 0) {
 327                                         break;
 328                                 }
 329                         }
 330                         free(seusrs);
 331 
 332                         if (eusr == NULL) {
 333                                 util_add_errmsg(errlst, gettext(
 334                                     "Project does not contain %s name \"%s\""),
 335                                     usrgrp, nusr);
 336                                 free(snusrs);
 337                                 goto out;
 338                         }
 339                 }
 340                 free(snusrs);
 341 
 342 
 343                 res = util_safe_zmalloc(1);
 344                 seusrs = eusrs = util_safe_strdup(*elist);
 345                 while ((eusr = strsep(&eusrs, sep)) != NULL) {
 346                         if (*eusr == '\0')
 347                                 continue;
 348                         snusrs = nusrs = util_safe_strdup(nlist);
 349                         while ((nusr = strsep(&nusrs, sep)) != NULL) {
 350                                 if (strcmp(eusr, nusr) == 0) {
 351                                         break;
 352                                 }
 353                         }
 354                         free(snusrs);
 355 
 356                         if (nusr == NULL) {
 357                                 if (*res != '\0')
 358                                         res = UTIL_STR_APPEND1(res, ",");
 359                                 res = UTIL_STR_APPEND1(res, eusr);
 360                         }
 361                 }
 362                 free(seusrs);
 363         } else if (flags & F_MOD_SUB || flags & F_MOD_REP) {
 364                 res = util_safe_strdup(nlist);
 365         }
 366 
 367 out:
 368         if (res != NULL) {
 369                 free(*elist);
 370                 *elist = res;
 371         }
 372 }
 373 
 374 char *
 375 projent_parse_users(char *nlist, int flags, lst_t *errlst)
 376 {
 377         char *ulist = NULL;
 378         char *susrs, *usrs, *usr;
 379         regex_t usernexp;
 380         char *sep;
 381 
 382         if (regcomp(&usernexp, USERN_EXP, REG_EXTENDED) != 0) {
 383                 util_add_errmsg(errlst, gettext(
 384                     "Failed to compile regular expression: \"%s\""),
 385                     USERN_EXP);
 386                 goto out;
 387         }
 388 
 389         sep = (flags & F_PAR_SPC) ? " ," : ",";
 390         susrs = usrs = util_safe_strdup(nlist);
 391         ulist = util_safe_zmalloc(1);
 392 
 393         while ((usr = strsep(&usrs, sep)) != NULL) {
 394                 if (*usr == '\0')
 395                         continue;
 396 
 397                 if (regexec(&usernexp, usr, 0, NULL, 0) != 0 &&
 398                     strcmp(usr, "*") != 0 &&
 399                     strcmp(usr, "!*") != 0) {
 400                         util_add_errmsg(errlst, gettext(
 401                             "Invalid user name \"%s\""), usr);
 402                         UTIL_FREE_SNULL(ulist);
 403                         break;
 404                 }
 405                 /* Append ',' first if required */
 406                 if (*ulist != '\0')
 407                         ulist = UTIL_STR_APPEND1(ulist, ",");
 408                 ulist = UTIL_STR_APPEND1(ulist, usr);
 409         }
 410 
 411         free(susrs);
 412         regfree(&usernexp);
 413 out:
 414         return (ulist);
 415 }
 416 
 417 
 418 char *
 419 projent_parse_groups(char *nlist, int flags, lst_t *errlst)
 420 {
 421         char *glist = NULL;
 422         char *sgrps, *grps, *grp;
 423         regex_t groupnexp;
 424         char *sep;
 425 
 426         if (regcomp(&groupnexp, GRUPN_EXP, REG_EXTENDED) != 0) {
 427                 util_add_errmsg(errlst, gettext(
 428                     "Failed to compile regular expression: \"%s\""),
 429                     GRUPN_EXP);
 430                 goto out;
 431         }
 432 
 433         sep = (flags & F_PAR_SPC) ? " ," : ",";
 434         sgrps = grps = util_safe_strdup(nlist);
 435         glist = util_safe_zmalloc(1);
 436 
 437         while ((grp = strsep(&grps, sep)) != NULL) {
 438                 if (*grp == '\0')
 439                         continue;
 440 
 441                 if (regexec(&groupnexp, grp, 0, NULL, 0) != 0 &&
 442                     strcmp(grp, "*") != 0 &&
 443                     strcmp(grp, "!*") != 0) {
 444                         util_add_errmsg(errlst, gettext(
 445                             "Invalid group name \"%s\""), grp);
 446                         UTIL_FREE_SNULL(glist);
 447                         break;
 448                 }
 449                 /* Append ',' first if required */
 450                 if (*glist != '\0')
 451                         glist = UTIL_STR_APPEND1(glist, ",");
 452                 glist = UTIL_STR_APPEND1(glist, grp);
 453         }
 454 
 455         free(sgrps);
 456         regfree(&groupnexp);
 457 out:
 458         return (glist);
 459 }
 460 
 461 int
 462 projent_parse_comment(char *comment, lst_t *errlst)
 463 {
 464         int ret = 0;
 465         if (strchr(comment, ':') != NULL) {
 466                 util_add_errmsg(errlst, gettext(
 467                     "Invalid Comment \"%s\": should not contain ':'"),
 468                     comment);
 469                 ret = 1;
 470         }
 471         return (ret);
 472 }
 473 
 474 int
 475 projent_validate_unique_id(lst_t *plst, projid_t projid, lst_t *errlst)
 476 {
 477         int e;
 478         projent_t *ent;
 479         for (e = 0; e < lst_size(plst); e++) {
 480                 ent = lst_at(plst, e);
 481                 if (ent->projid == projid) {
 482                         util_add_errmsg(errlst, gettext(
 483                             "Duplicate projid \"%d\""), projid);
 484                         return (1);
 485                 }
 486         }
 487         return (0);
 488 }
 489 int
 490 projent_validate_projid(projid_t projid, int flags, lst_t *errlst)
 491 {
 492         projid_t maxprojid;
 493 
 494         maxprojid = (flags & F_PAR_RES) ? 0 : 100;
 495 
 496         if (projid < maxprojid) {
 497                 util_add_errmsg(errlst, gettext(
 498                     "Invalid projid \"%d\": "
 499                     "must be >= 100"),
 500                     projid);
 501                 return (1);
 502         }
 503         return (0);
 504 }
 505 
 506 int
 507 projent_parse_projid(char *projidstr, projid_t *pprojid, lst_t *errlst)
 508 {
 509         char *ptr;
 510         long long llid;
 511         regex_t prjidexp;
 512         int ret = 0;
 513 
 514         if (regcomp(&prjidexp, PRJID_EXP, REG_EXTENDED) != 0) {
 515                 util_add_errmsg(errlst, gettext(
 516                     "Failed to compile regular expression: \"%s\""), PRJID_EXP);
 517                 return (1);
 518         }
 519 
 520 
 521         if (regexec(&prjidexp, projidstr, 0, NULL, 0) != 0) {
 522                 util_add_errmsg(errlst, gettext("Invalid project id: \"%s\""),
 523                     projidstr);
 524                 ret = 1;
 525                 goto out;
 526         }
 527 
 528         llid = strtoll(projidstr, &ptr, 10);
 529 
 530         /* projid should be a positive number */
 531         if (llid == 0 && errno == ERANGE && *ptr != '\0') {
 532                 util_add_errmsg(errlst, gettext("Invalid project id: \"%s\""),
 533                     projidstr);
 534                 ret = 1;
 535                 goto out;
 536         }
 537 
 538         /* projid should be a positive number >= 0 */
 539         if (llid < 0) {
 540                 util_add_errmsg(errlst, gettext(
 541                     "Invalid projid \"%lld\": must be >= 0"), llid);
 542                 ret = 1;
 543                 goto out;
 544         }
 545 
 546         /* projid should be less than UID_MAX */
 547         if (llid > INT_MAX) {
 548                 util_add_errmsg(errlst, gettext(
 549                     "Invalid projid \"%lld\": must be <= %d"),
 550                     llid, INT_MAX);
 551                 ret = 1;
 552                 goto out;
 553         }
 554 
 555         if (pprojid != NULL)
 556                 *pprojid = llid;
 557 out:
 558         regfree(&prjidexp);
 559         return (ret);
 560 }
 561 
 562 int
 563 projent_validate_unique_name(lst_t *plst, char *pname, lst_t *errlst)
 564 {
 565         int e;
 566         projent_t *ent;
 567         for (e = 0; e < lst_size(plst); e++) {
 568                 ent = lst_at(plst, e);
 569                 if (strcmp(ent->projname, pname) == 0) {
 570                         util_add_errmsg(errlst, gettext(
 571                             "Duplicate project name \"%s\""), pname);
 572                         return (1);
 573                 }
 574         }
 575         return (0);
 576 }
 577 
 578 int
 579 projent_parse_name(char *pname, lst_t *errlst)
 580 {
 581         int ret = 1;
 582         regex_t projnexp;
 583         if (regcomp(&projnexp, PROJN_EXP, REG_EXTENDED) != 0) {
 584                 util_add_errmsg(errlst, gettext(
 585                     "Failed to compile regular expression: \"%s\""),
 586                     PROJN_EXP);
 587                 goto out;
 588         }
 589 
 590         if (regexec(&projnexp, pname, 0, NULL, 0) != 0) {
 591                 util_add_errmsg(errlst, gettext(
 592                     "Invalid project name \"%s\", "
 593                     "contains invalid characters"), pname);
 594         } else if (strlen(pname) > PROJNAME_MAX) {
 595                 util_add_errmsg(errlst, gettext(
 596                     "Invalid project name \"%s\", "
 597                     "name too long"), pname);
 598         } else {
 599                 ret = 0;
 600         }
 601 
 602         regfree(&projnexp);
 603 out:
 604         return (ret);
 605 }
 606 
 607 void
 608 projent_free(projent_t *ent)
 609 {
 610         free(ent->projname);
 611         free(ent->comment);
 612         free(ent->userlist);
 613         free(ent->grouplist);
 614         attrib_free_lst(ent->attrs);
 615         free(ent->attrs);
 616 }
 617 
 618 projent_t *
 619 projent_parse_components(char *projname, char *idstr, char *comment,
 620     char *users, char *groups, char *attr, int flags, lst_t *errlst)
 621 {
 622         projent_t *ent;
 623         int reterr = 0;
 624 
 625         ent = util_safe_zmalloc(sizeof (projent_t));
 626 
 627 
 628         ent->projname = util_safe_strdup(projname);
 629         ent->comment = util_safe_strdup(comment);
 630 
 631         reterr += projent_parse_name(ent->projname, errlst);
 632         reterr += projent_parse_projid(idstr, &ent->projid, errlst);
 633         reterr += projent_parse_comment(ent->comment, errlst);
 634         ent->userlist = projent_parse_users(users, flags, errlst);
 635         ent->grouplist = projent_parse_groups(groups, flags, errlst);
 636         ent->attrs = projent_parse_attributes(attr, flags, errlst);
 637 
 638         if (reterr > 0 || ent->userlist == NULL ||
 639             ent->grouplist == NULL || ent->attrs == NULL) {
 640                 projent_free(ent);
 641                 UTIL_FREE_SNULL(ent);
 642         }
 643 
 644         return (ent);
 645 }
 646 projent_t *
 647 projent_parse(char *projstr, int flags, lst_t *errlst)
 648 {
 649         char *str, *sstr;
 650         char *projname, *idstr, *comment, *users, *groups, *attrstr;
 651         projent_t *ent;
 652 
 653         if (projstr == NULL)
 654                 return (NULL);
 655 
 656         projname = idstr = comment = users = groups = attrstr = NULL;
 657         ent = NULL;
 658 
 659         sstr  = str = util_safe_strdup(projstr);
 660 
 661         if ((projname = util_safe_strdup(strsep(&str, ":"))) == NULL ||
 662             (idstr = util_safe_strdup(strsep(&str, ":"))) == NULL ||
 663             (comment = util_safe_strdup(strsep(&str, ":"))) == NULL ||
 664             (users = util_safe_strdup(strsep(&str, ":"))) == NULL ||
 665             (groups = util_safe_strdup(strsep(&str, ":"))) == NULL ||
 666             (attrstr = util_safe_strdup(strsep(&str, ":"))) == NULL ||
 667             strsep(&str, ":") != NULL) {
 668                 util_add_errmsg(errlst, gettext(
 669                     "Incorrect number of fields.  Should have 5 \":\"'s."));
 670                 goto out;
 671         }
 672 
 673         ent = projent_parse_components(projname, idstr, comment, users, groups,
 674             attrstr, flags, errlst);
 675 out:
 676         free(sstr);
 677         free(projname); free(idstr); free(comment);
 678         free(users); free(groups); free(attrstr);
 679         return (ent);
 680 }
 681 
 682 
 683 void
 684 projent_free_lst(lst_t *plst)
 685 {
 686         projent_t *ent;
 687 
 688         if (plst == NULL)
 689                 return;
 690 
 691         while (!lst_is_empty(plst)) {
 692                 ent = lst_at(plst, 0);
 693                 (void) lst_remove(plst, ent);
 694                 projent_free(ent);
 695                 free(ent);
 696         }
 697 }
 698 
 699 
 700 void
 701 projent_put_lst(char *projfile, lst_t *plst, lst_t *errlst)
 702 {
 703         char *tmpprojfile, *attrs;
 704         FILE *fp;
 705         projent_t *ent;
 706         struct stat statbuf;
 707         int e, ret;
 708 
 709         tmpprojfile = NULL;
 710         if (asprintf(&tmpprojfile, "%s.%ld_tmp", projfile, getpid()) == -1) {
 711                 util_add_errmsg(errlst, gettext(
 712                     "Failed to allocate memory"));
 713                 goto out;
 714         }
 715 
 716         if (stat(projfile, &statbuf) != 0) {
 717                 util_add_errmsg(errlst, gettext(
 718                     "Failed to access %s: %s"),
 719                     projfile, strerror(errno));
 720                 goto out;
 721         }
 722         if ((fp = fopen(tmpprojfile, "wx")) == NULL) {
 723                 util_add_errmsg(errlst, gettext(
 724                     "Cannot create %s: %s"),
 725                     tmpprojfile, strerror(errno));
 726                 goto out;
 727         }
 728 
 729         for (e = 0; e < lst_size(plst); e++) {
 730                 ent = lst_at(plst, e);
 731                 attrs = attrib_lst_tostring(ent->attrs);
 732                 ret = fprintf(fp, "%s:%ld:%s:%s:%s:%s\n", ent->projname,
 733                     ent->projid, ent->comment, ent->userlist, ent->grouplist,
 734                     attrs);
 735                 free(attrs);
 736                 if (ret < 0) {
 737                         util_add_errmsg(errlst, gettext(
 738                             "Failed to write to  %s: %s"),
 739                             tmpprojfile, strerror(errno));
 740                         /* Remove the temporary file and exit */
 741                         (void) unlink(tmpprojfile);
 742                         goto out1;
 743                 }
 744         }
 745 
 746         if (chown(tmpprojfile, statbuf.st_uid, statbuf.st_gid) != 0) {
 747                 util_add_errmsg(errlst, gettext(
 748                     "Cannot set ownership of  %s: %s"),
 749                     tmpprojfile, strerror(errno));
 750                 (void) unlink(tmpprojfile);
 751                 goto out1;
 752         }
 753 
 754         if (rename(tmpprojfile, projfile) != 0) {
 755                 util_add_errmsg(errlst, gettext(
 756                     "Cannot rename %s to %s : %s"),
 757                     tmpprojfile, projfile, strerror(errno));
 758                 (void) unlink(tmpprojfile);
 759                 goto out1;
 760         }
 761 
 762 out1:
 763         (void) fclose(fp);
 764 out:
 765         free(tmpprojfile);
 766 }
 767 
 768 lst_t *
 769 projent_get_lst(char *projfile, int flags, lst_t *errlst)
 770 {
 771         FILE *fp;
 772         lst_t *plst;
 773         int line = 0;
 774         char *buf = NULL, *nlp;
 775         size_t cap = 0;
 776         projent_t *ent;
 777 
 778         plst = util_safe_malloc(sizeof (lst_t));
 779         lst_create(plst);
 780 
 781         if ((fp = fopen(projfile, "r")) == NULL) {
 782                 if (errno == ENOENT) {
 783                         /*
 784                          * There is no project file,
 785                          * return an empty lst
 786                          */
 787                         return (plst);
 788                 } else {
 789                         /* Report the error unable to open the file */
 790                         util_add_errmsg(errlst, gettext(
 791                             "Cannot open %s: %s"),
 792                             projfile, strerror(errno));
 793 
 794                         free(plst);
 795                         return (NULL);
 796                 }
 797         }
 798 
 799         while ((getline(&buf, &cap, fp)) != -1 && ++line) {
 800 
 801                 if ((nlp = strchr(buf, '\n')) != NULL)
 802                         *nlp = '\0';
 803 
 804                 if ((ent = projent_parse(buf, flags, errlst)) != NULL) {
 805                         lst_insert_tail(plst, ent);
 806                 } else {
 807                         /* Report the error */
 808                         util_add_errmsg(errlst, gettext(
 809                             "Error parsing: %s line: %d: \"%s\""),
 810                             projfile, line, buf);
 811 
 812                         /* free the allocated resources */
 813                         projent_free_lst(plst);
 814                         UTIL_FREE_SNULL(plst);
 815                         goto out;
 816                 }
 817         }
 818 
 819         if (flags & F_PAR_VLD && plst != NULL) {
 820                 if (projent_validate_lst(plst, flags, errlst) != 0) {
 821                         projent_free_lst(plst);
 822                         UTIL_FREE_SNULL(plst);
 823                 }
 824         }
 825 
 826 out:
 827         (void) fclose(fp);
 828         free(buf);
 829         return (plst);
 830 }