/* * COPYRIGHT NOTICE * Copyright 1990, Silicon Graphics, Inc. All Rights Reserved. * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.; * the contents of this file may not be disclosed to third parties, copied or * duplicated in any form, in whole or in part, without the prior written * permission of Silicon Graphics, Inc. * * RESTRICTED RIGHTS LEGEND: * Use, duplication or disclosure by the Government is subject to restrictions * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data * and Computer Software clause at DFARS 252.227-7013, and/or in similar or * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished - * rights reserved under the Copyright Laws of the United States. * */ /* * userck - verify correctness of user.info */ #ident "$Revision: 1.5 $" #include #include #include #include mac_label access_label = {MSEN_HIGH_LABEL, MINT_LOW_LABEL, }; mac_label userinfo_label = {MSEN_ADMIN_LABEL, MINT_HIGH_LABEL, }; mac_label passwd_label = {MSEN_LOW_LABEL, MINT_HIGH_LABEL, }; char *userinfo_path = "/secadm/auth/user.info"; char *passwd_path = "/secadm/etc/passwd"; char *passwd_link = "/etc/passwd"; char *root_name = "root"; char *dbadmin_name = "dbadmin"; main(int argc, char *argv[], char **envp) { extern char *optarg; /* For use by getopt(3) */ extern int optind; /* For use by getopt(3) */ extern int optind; /* For use by getopt(3) */ int c; /* For use by getopt(3) */ int vflag = 0; /* verbose mode flag */ int result = 0; /* exit code */ char line[256]; /* line buffer */ char *cp; /* char manipulation */ struct stat sbuf; /* stat(2) result buffer */ mac_label label; /* The desired label value */ mac_label *low_lp; /* user's low label */ mac_label *high_lp; /* user's high label */ userinfo_t *urp; /* to look up user name */ userinfo_t *wurp; /* to look up user name */ userinfo_t *root_ur; /* user information for root */ userinfo_t *dbadmin_ur; /* user information for dbadmin */ FILE *fp; /* input from user.info */ while ((c = getopt(argc, argv, "v")) != -1) { switch (c) { case 'v': vflag++; break; case '?': default: fprintf(stderr, "userck: unknown option '%c'\n", c); exit(1); } } if (getuid() != 0) fprintf(stderr, "userck: Without root privilege your results may not be accurate\n"); else _sgi_setplabel(&access_label); /* * Get entrys for expected user id's. */ if ((root_ur = getuserinfonam(root_name)) == NULL) { printf("userck: Expected entry for %s not found\n", root_name); result = 1; } if ((dbadmin_ur = getuserinfonam(dbadmin_name)) == NULL) { printf("userck: Expected entry for %s not found\n", dbadmin_name); result = 1; } /* * Check the access control information of all three files. * * Do user.info first. */ if (lstat(userinfo_path, &sbuf) < 0) { printf("userck: failure stating %s\n", userinfo_path); result = 1; } else { if (!((root_ur && (sbuf.st_uid == root_ur->ur_uid)) || (dbadmin_ur && (sbuf.st_uid == dbadmin_ur->ur_uid)))) { if ((urp = getuserinfouid(sbuf.st_uid)) != NULL) { printf( "userck: Owner of %s is incorrectly %s.\n", userinfo_path, urp->ur_name); free(urp); } else printf( "userck: Owner of %s is incorrectly %d.\n", userinfo_path, sbuf.st_uid); result = 1; } } if (_sgi_getlabel(userinfo_path, &label) < 0) { printf("userck: failure getting label for %s\n", userinfo_path); result = 1; } /* * Do passwd file next */ if (lstat(passwd_path, &sbuf) < 0) { printf("userck: failure stating %s\n", passwd_path); result = 1; } else { if (!((root_ur && (sbuf.st_uid == root_ur->ur_uid)) || (dbadmin_ur && (sbuf.st_uid == dbadmin_ur->ur_uid)))) { if ((urp = getuserinfouid(sbuf.st_uid)) != NULL) { printf( "userck: Owner of %s is incorrectly %s.\n", passwd_path, urp->ur_name); free(urp); } else printf( "userck: Owner of %s is incorrectly %d.\n", passwd_path, sbuf.st_uid); result = 1; } } if (_sgi_getlabel(passwd_path, &label) < 0) { printf("userck: failure getting label for %s\n", passwd_path); result = 1; } /* * Do passwd link last */ if (lstat(passwd_link, &sbuf) < 0) { printf("userck: failure stating %s\n", passwd_link); result = 1; } else { if (!((root_ur && (sbuf.st_uid == root_ur->ur_uid)) || (dbadmin_ur && (sbuf.st_uid == dbadmin_ur->ur_uid)))) { if ((urp = getuserinfouid(sbuf.st_uid)) != NULL) { printf( "userck: Owner of %s is incorrectly %s.\n", passwd_link, urp->ur_name); free(urp); } else printf( "userck: Owner of %s is incorrectly %d.\n", passwd_link, sbuf.st_uid); result = 1; } } if (_sgi_getlabel(passwd_link, &label) < 0) { printf("userck: failure getting label for %s\n", passwd_link); result = 1; } /* * For each entry in user.info verify a valid return from * each of getuserinfonam() and getuserinfoid(). */ if ((fp = fopen(userinfo_path, "r")) == NULL) { printf("userck: cannot open %s\n", userinfo_path); result = 1; } for (c = 1; fp && fgets(line, 255, fp) != NULL; c++) { if (index(line, '\n') == NULL) { printf( "userck: user.info line %d too long\n", c); result = 1; } if (line[0] == '#') continue; if ((cp = index(line, ':')) == NULL) { printf( "userck: user.info line %d has no colons\n", c); result = 1; continue; } *cp++ = '\0'; if ((cp = index(cp, ':')) != NULL) cp++; if ((urp = getuserinfonam(line)) == NULL) { printf( "userck: user %s has no passwd file entry (user.info line %d).\n", line, c); result = 1; } else free(urp); if ((urp = getuserinfouid(atoi(cp))) == NULL) { printf( "userck: uid %d has no passwd file entry (user.info line %d).\n", atoi(cp), c); result = 1; } else free(urp); } if (fp != NULL) fclose(fp); /* * For each entry in passwd verify a valid return from * each of getuserinfonam() and getuserinfoid(). */ if ((fp = fopen(passwd_path, "r")) == NULL) { printf("userck: cannot open %s\n", passwd_path); result = 1; } for (c = 1; fp && fgets(line, 255, fp) != NULL; c++) { if (index(line, '\n') == NULL) { printf( "userck: passwd line %d too long\n", c); result = 1; } if ((cp = index(line, ':')) == NULL) { printf( "userck: passwd line %d has no colons\n", c); result = 1; continue; } *cp++ = '\0'; if ((cp = index(cp, ':')) != NULL) cp++; if ((urp = getuserinfonam(line)) == NULL) { printf( "userck: user %s has no user.info file entry (passwd line %d).\n", line, c); result = 1; } else { free(urp); if ((urp = getuserinfouid(atoi(cp))) == NULL) { printf( "userck: uid %d has no user.info file entry (passwd line %d).\n", atoi(cp), c); result = 1; } else free(urp); } } if (fp != NULL) fclose(fp); /* * For each entry in user.info verify * 1. There is a password * 2. The home directory exists and * it's at the user's lowest label, or * it's at least within the user's range * 3. The user's shell is always accessable * 4. The clearance range makes sense. */ if ((fp = fopen(userinfo_path, "r")) == NULL) { printf("userck: cannot open %s\n", userinfo_path); result = 1; } for (c = 1; fp && fgets(line, 255, fp) != NULL; c++) { if (index(line, '\n') == NULL) continue; if (line[0] == '#') continue; if ((cp = index(line, ':')) == NULL) continue; *cp++ = '\0'; if ((urp = getuserinfonam(line)) == NULL) continue; if (strlen(urp->ur_passwd) == 0) { printf( "userck: user %s has no password.\n", urp->ur_name); result = 1; } /* * Check the user's home directory. */ if (stat(urp->ur_dir, &sbuf) < 0) { printf( "userck: user %s has no home \"%s\".\n", urp->ur_name, urp->ur_dir); result = 1; } else { if ((sbuf.st_mode & S_IFDIR) == 0) { printf( "userck: user %s's home \"%s\" is not a directory.\n", urp->ur_name, urp->ur_dir); result = 1; } if (sbuf.st_uid != urp->ur_uid) { if ((wurp=getuserinfouid(sbuf.st_uid)) == NULL){ printf( "userck: user %s's home \"%s\" owned by %d.\n", urp->ur_name, urp->ur_dir, sbuf.st_uid); result = 1; } else { printf( "userck: user %s's home \"%s\" owned by %s.\n", urp->ur_name, urp->ur_dir, wurp->ur_name); free(wurp); result = 1; } } } if (_sgi_getlabel(urp->ur_dir, &label) >= 0) { switch (c = mac_clearedlbl(urp, &label)) { case MAC_CLEARED: break; case MAC_LBL_TOO_LOW: printf( "userck: user %s's home %s is below user's clearance.\n", urp->ur_name, urp->ur_dir); break; case MAC_INCOMPARABLE: printf( "userck: user %s's home %s is not comparable to user's clearance.\n", urp->ur_name, urp->ur_dir); break; case MAC_LBL_TOO_HIGH: printf( "userck: user %s's home %s is above user's clearance.\n", urp->ur_name, urp->ur_dir); break; case MAC_MSEN_EQUAL: printf( "userck: user %s's home %s is at equal sensitivity.\n", urp->ur_name, urp->ur_dir); break; case MAC_MINT_EQUAL: printf( "userck: user %s's home %s is at equal integrity.\n", urp->ur_name, urp->ur_dir); break; case MAC_NULL_CLEARANCE: case MAC_BAD_USER_INFO: printf( "userck: clearance error while checking home directory of %s : \n\t\t%s\n",urp->ur_name,mac_clearance_error(c)); break; default: printf( "userck: Program error (mac_clearedlbl returned bad value %d)\n",c); break; } } /* * Check the user's shell. */ if (*urp->ur_shell == '\0') { printf("userck: user %s has no shell.\n", urp->ur_name); result = 1; } else if (stat(urp->ur_shell, &sbuf) < 0) { printf( "userck: user %s's shell \"%s\" does not exist.\n", urp->ur_name, urp->ur_shell); result = 1; } else { if ((sbuf.st_mode & S_IFREG) == 0) { printf( "userck: user %s's shell \"%s\" is not a file.\n", urp->ur_name, urp->ur_shell); result = 1; } if ((sbuf.st_mode & 0111) == 0) { printf( "userck: user %s's shell \"%s\" is not executable.\n", urp->ur_name, urp->ur_shell); result = 1; } } if (_sgi_getlabel(urp->ur_shell, &label) >= 0) { switch (c = mac_clearedlbl(urp, &label)) { case MAC_CLEARED: case MAC_LBL_TOO_LOW: break; case MAC_INCOMPARABLE: printf( "userck: user %s's shell %s is not comparable to user's clearance.\n", urp->ur_name, urp->ur_shell); break; case MAC_LBL_TOO_HIGH: printf( "userck: user %s's shell %s is above user's clearance.\n", urp->ur_name, urp->ur_shell); break; case MAC_MSEN_EQUAL: printf( "userck: user %s's shell %s is at equal sensitivity.\n", urp->ur_name, urp->ur_shell); break; case MAC_MINT_EQUAL: printf( "userck: user %s's shell %s is at equal integrity.\n", urp->ur_name, urp->ur_shell); break; case MAC_NULL_CLEARANCE: case MAC_BAD_USER_INFO: printf( "userck: clearance error while checking shell of %s : \n\t\t%s\n",urp->ur_name,mac_clearance_error(c)); break; default: printf( "userck: Program error (mac_clearedlbl returned bad value %d)\n",c); break; } } /* * To check to make sure the default login label is within * the clearance range(s). */ if ((c = mac_cleared(urp, urp->ur_deflabel)) != MAC_CLEARED ) { switch (c) { case MAC_BAD_REQD_LBL: if (strlen(urp->ur_deflabel) > 0) printf( "userck: user %s's default label \"%s\" is bad.\n", urp->ur_name,urp->ur_deflabel); break; case MAC_LBL_TOO_LOW: printf( "userck: user %s's default label \"%s\" is below their clearance.\n", urp->ur_name, urp->ur_deflabel); break; case MAC_INCOMPARABLE: printf( "userck: user %s's default label \"%s\" is not comparable to user's clearance.\n", urp->ur_name, urp->ur_deflabel); break; case MAC_LBL_TOO_HIGH: printf( "userck: user %s's default label \"%s\" is above their clearance.\n", urp->ur_name, urp->ur_deflabel); break; case MAC_MSEN_EQUAL: printf( "userck: user %s's default label \"%s\" is at equal sensitivity.\n", urp->ur_name, urp->ur_deflabel); break; case MAC_MINT_EQUAL: printf( "userck: user %s's default label \"%s\" is at equal integrity.\n", urp->ur_name, urp->ur_deflabel); break; case MAC_NULL_CLEARANCE: case MAC_BAD_USER_INFO: printf( "userck: clearance error while checking default label of %s : \n\t\t%s\n",urp->ur_name,mac_clearance_error(c)); break; default: printf( "userck: Program error (mac_clearedlbl returned bad value %d)\n",c); break; } } free(urp); } if (fp != NULL) fclose(fp); /* * Uniqueness checks in user.info file. */ if ((fp = fopen(userinfo_path, "r")) == NULL) { printf("userck: cannot open %s\n", userinfo_path); result = 1; } for (c = 1; fp && fgets(line, 255, fp) != NULL; c++) { FILE *nfp; char name[256]; int uid; int cc; if (index(line, '\n') == NULL) continue; if (line[0] == '#') continue; if ((cp = index(line, ':')) == NULL) continue; *cp++ = '\0'; if ((nfp = fopen(userinfo_path, "r")) == NULL) { printf("userck: cannot open %s\n", userinfo_path); result = 1; continue; } for (cc = 1; nfp && fgets(name, 255, nfp) != NULL; cc++) { if (index(name, '\n') == NULL) continue; if (name[0] == '#') continue; if ((cp = index(name, ':')) == NULL) continue; *cp++ = '\0'; if (strcmp(name, line) == 0 && c != cc) printf( "userck: user.info has duplicate name %s at lines %d and %d.\n", name, c, cc); } fclose(nfp); } if (fp != NULL) fclose(fp); /* * Uniqueness checks in password file. */ if ((fp = fopen(passwd_path, "r")) == NULL) { printf("userck: cannot open %s\n", passwd_path); result = 1; } for (c = 1; fp && fgets(line, 255, fp) != NULL; c++) { FILE *nfp; char name[256]; int uid; int cc; if (index(line, '\n') == NULL) continue; if (line[0] == '#') continue; if ((cp = index(line, ':')) == NULL) continue; *cp++ = '\0'; if ((cp = index(cp, ':')) != NULL) cp++; uid = atoi(cp); if ((nfp = fopen(passwd_path, "r")) == NULL) { printf("userck: cannot open %s\n", passwd_path); result = 1; continue; } for (cc = 1; nfp && fgets(name, 255, nfp) != NULL; cc++) { if (index(name, '\n') == NULL) continue; if (name[0] == '#') continue; if ((cp = index(name, ':')) == NULL) continue; *cp++ = '\0'; if ((cp = index(cp, ':')) != NULL) cp++; if (strcmp(name, line) == 0 && c != cc) printf( "userck: passwd has duplicate name %s at lines %d and %d.\n", name, c, cc); if (uid == atoi(cp) && c != cc) printf( "userck: passwd has duplicate uid %d at lines %d and %d.\n", uid, c, cc); } fclose(nfp); } if (fp != NULL) fclose(fp); exit(result); }