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