DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 
Using trusted facilities

loge.c example

The loge.c program allows users who have the appropriate authorization to execute a command with super-user privileges. Users must supply a password for verification. They do not need to supply the super-user password. loge.c can be used with any command whose executable file is in the /tcb/files/valhalla directory. Each command can also define a secondary subsystem authorization.

The logged-in user (LUID) is authorized if they have either the ``wotan'' primary subsystem authorization or the secondary subsystem authorization defined for the command issued under loge.c.

This program must be installed with both setuid root and setgid wotan.

This program demonstrates how to:

Compile and install this program with the following command:

cc loge.c -lprot -lx -o loge
chown root loge
chgrp wotan loge
chmod 6111 loge

loge.c (Part 1/17)

  1 #define SecureWare			/* enable security features		*/

2 #include <sys/types.h> /* system pseudo-types */ 3 #include <errno.h> /* system error definitions */ 4 #include <stdio.h> /* standard I/O definitions */ 5 #include <ctype.h> /* character classification */ 6 #include <string.h> /* string library definitions */ 7 #include <stdarg.h> /* variable-len argument lists */ 8 #include <unistd.h> /* access(S) definitions */ 9 #include <sys/stat.h> /* stat(S) definitions */ 10 #include <time.h> /* localtime() definitions */ 11 #include <sys/security.h> /* various security definitions */ 12 #include <sys/audit.h> /* audit definitions */ 13 #include <prot.h> /* database definitions */

14 extern char *ttyname(int), *defread(char *); 15 extern int defopen(char *);

16 #define TRUE 1 17 #define FALSE 0

18 #define ARBSTRSIZ 300 /* ARBitrary STRing SIZe */ 19 #define MAXCMDLEN ARBSTRSIZ /* MAXimum CoMmanD name LENgth */

20 char primary_subsystem[] = "wotan"; 21 char valhalla[] = "/tcb/files/valhalla"; 22 char su_defaults[] = "/etc/default/su";

23 void syserror(int, char *, ...);

24 void sulog(char *, int, char **); 25 void failed(int, char *, char **);

loge.c (Part 2/17)

26 #define TCB_ANY_TYPE ' ' /* any type of file */ 27 #define TCB_FILE 'r' /* regular file */ 28 #define TCB_DIRECTORY 'd' /* directory */

29 int check_TCB_path(char *, char, char *); 30 int check_DAC_path(char *, char, char *);

31 enum DAC_status { 32 NotListed, /* file not listed in File Control database */ 33 NoSuchFile, /* file does not exist */ 34 WrongDAC, /* existing file does not meet required DAC */ 35 MatchesDAC, /* existing file has exactly the required DAC */ 36 ExceedsDAC /* existing file grants less access than required */ 37 } compare_DAC_attributes(char *, struct pr_file *);

38 main( 39 int argc, 40 char *argv[] 41 ) { 42 struct pr_passwd *pr_pw; /* Protected Password entry */ 43 char path[sizeof(valhalla) + 1 + MAXCMDLEN + 1]; 44 char temp[sizeof(path) + ARBSTRSIZ]; 45 char *clear, *cipher; /* Clear-, cipher-text password */ 46 int password_required; /* TRUE if must have a password */ 47 int has_password; /* TRUE if has a password */ 48 int is_proper; /* TRUE if knows password */

loge.c (Part 3/17)

49 set_auth_parameters(argc, argv);

50 if (argc < 2 || *argv[1] == ' ') { 51 (void) fprintf(stderr, 52 "Usage: %s cmd [ args ]...\n", 53 command_name 54 ); 55 failed(2, (char *)0, &argv[1]); 56 /* NOTREACHED */ 57 } 58 if (strchr(argv[1], '/') != (char *)0 || strlen(argv[1]) > MAXCMDLEN) { 59 (void) fprintf(stderr, 60 "%s: Not the name of a command: %s\n", 61 command_name, argv[1] 62 ); 63 failed(1, (char *)0, &argv[1]); 64 /* NOTREACHED */ 65 }


line 49
This line initializes the authentication routines. This must be the first function called in the main() routine. A side effect of this call is that the umask is changed to 077.

lines 50-65
The command must be issued with at least one argument that corresponds to the base name of an executable file in the /tcb/files/valhalla directory. This program provides this information directly within the main routine rather than using a separate subroutine as the prwarn.c example did. Lines 154-164 define the failed subroutine.

loge.c (Part 4/17)

 66 	if ( ! authorized_user(primary_subsystem) && ! authorized_user(argv[1])) {
 67 		(void) fprintf(stderr,
 68 			"Sorry, not authorized to run %s.\n",
 69 			argv[1]
 70 		);
 71 		failed(1, (char *)0, &argv[1]);
 72 		/* NOTREACHED */
 73 	}

74 (void) sprintf(path, "%s/%s", valhalla, argv[1]); 75 if (eaccess(path, X_OK)) { 76 syserror(errno, "%s is not an executable command", path); 77 failed(1, (char *)0, &argv[1]); 78 /* NOTREACHED */ 79 }


lines 66-73
These lines check the permissions of the logged-in user. The user must either have the primary subsystem authorization (``wotan'') or must have the specific secondary subsystem authorization associated with the specified command. After this check is passed, we know that the LUID is authorized. Consequently, there is no need to disguise any failures or otherwise hide any information.

lines 74-79
These lines check that the specified command exists in the valhalla directory and that it is executable.

loge.c (Part 5/17)

 80 	if (check_TCB_path(path, TCB_FILE, "restricted command")) {
 81 		(void) fprintf(stderr,
 82 			"%s: The system's integrity may be compromised.\n",
 83 			command_name
 84 		);
 85 		failed(1, (char *)0, &argv[1]);
 86 		/* NOTREACHED */
 87 	}

88 if ((pr_pw = getprpwuid(starting_luid())) == (struct pr_passwd *)0 || 89 ! pr_pw->uflg.fg_name 90 ) { 91 (void) sprintf(temp, "UID %d", starting_luid()); 92 audit_auth_entry(temp, OT_PRPWD, 93 "User missing from Protected Password database" 94 ); 95 (void) fprintf(stderr, 96 "%s: Cannot obtain authentication data for %s", 97 command_name, temp 98 ); 99 failed(1, (char *)0, &argv[1]); 100 /* NOTREACHED */ 101 }

102 #ifdef AUTH_U_NULLPW /* #define'd in 3.2v2.0 */ 103 if (pr_pw->uflg.fg_nullpw) 104 password_required = ( ! pr_pw->ufld.fd_nullpw); 105 else if (pr_pw->sflg.fg_nullpw) 106 password_required = ( ! pr_pw->sfld.fd_nullpw); 107 else 108 #endif 109 password_required = TRUE;

110 if (pr_pw->uflg.fg_encrypt && *pr_pw->ufld.fd_encrypt) { 111 has_password = TRUE; 112 cipher = pr_pw->ufld.fd_encrypt; 113 } 114 else { 115 has_password = FALSE; 116 cipher = "*"; /* not a valid encrypted password */ 117 }


lines 80-87
These lines check that the file conforms to the specification listed in the File Control database.

lines 88-101
These lines get the subsystem authorization vector for the LUID. Because the user has logged in previously, there must be a Protected Password Entry; if not, this is an auditable problem. It also checks that the LUID has a name, because you need the name later (and all Protected Password entries must have names).

lines 102-117
These lines check whether the LUID needs a password. Before Release 3.2, Version 2.0 and SLS UNX 223, passwords were always required.

line 112
Empty cipher text is the same as no password.

loge.c (Part 6/17)

118 if (password_required || has_password) { 119 clear = getpasswd("Password:", AUTH_MAX_PASSWD_LENGTH); 120 is_proper = (strcmp(cipher, bigcrypt(clear, cipher)) == 0); 121 (void) getpasswd((char *)0, AUTH_MAX_PASSWD_LENGTH); 122 if (is_proper) { 123 (void) sprintf(temp, 124 "Password correct - run %s as superuser", 125 path 126 ); 127 sa_audit_subsystem(ST_AUTH, "Check password", temp); 128 } 129 else { 130 (void) sprintf(temp, 131 "Password incorrect - command %s not run", 132 path 133 ); 134 sa_audit_subsystem(ST_AUTH, "Check password", temp); 135 (void) fputs("Sorry.\n", stderr); 136 failed(1, pr_pw->ufld.fd_name, &argv[1]); 137 /* NOTREACHED */ 138 } 139 }

140 sulog(pr_pw->ufld.fd_name, TRUE, &argv[1]);

141 endprpwent(); /* Close Protected Password database */ 142 endprfient(); /* Close File Control database */

143 if (putenv("PATH=/bin:/etc:/usr/bin:/tcb/bin") || putenv("IFS= \t\n")) 144 audit_no_resource("environment", OT_MEMORY, "cannot change"); 145 else if (setgid(starting_rgid())) 146 syserror(errno, "Cannot reset GID"); 147 else { 148 (void) execv(path, &argv[1]); 149 syserror(errno, "Could not run %s", path); 150 } 151 exit(3); 152 /* NOTREACHED */ 153 }


lines 118-140
These lines request the user to supply the password for the LUID and authenticate it. The ``Orange Book'' requires audit of ``use of authentication mechanisms.''

bigcrypt( ) is a function that has the same parameters and function as the traditional crypt( ) library routine. In addition, it implements an extension to the crypt function to support longer passwords.\*(F

The password encryption scheme on SCO OpenServer is designed to have compatibility with earlier UNIX system and XENIX password encryption, and to have the ability to use passwords with more than 8 significant characters. Long passwords allow the use of ``pass-phrases'' such as This is my password string. This allows easy to remember passwords and reduces the risk of a password being comprised by a dictionary-based attack. In XENIX and earlier UNIX system implementation, this password example is treated as if the user had only entered ``This is '' because only the first 8 characters are used for encryption.

In SCO UNIX systems, Release 3.2, the first 8 characters are still encrypted as before. Any characters following this in the clear-text password are then encrypted in groups of up to 8 characters each, using a salt\*(F derived from the preceding encrypted segment, and added to the end of the encrypted string.

No check is made to verify that the user exists and is not locked out of the system, because it is not possible for the user to execute this code without being logged in.


line 118
This check is done if either the LUID requires a password or has a password assigned to it. The password_required and has_password constants are defined in lines 46 and 47.

lines 123-125
If the user supplies the correct password, a message is sent to the Audit Trail that the user can execute this command as super user.

line 140
An entry is made in the super-user log if it is enabled to record that the user got super-user privileges. This log is also updated when a user successfully executes the su(C) command to become super user. See lines 167-207 for the definition of the sulog function.

lines 141-153
These lines install safe values of PATH and IFS in the environment, reset the EGID (currently ``wotan'') to the current RGID, and then execute the command with any arguments supplied in the command line. The EUID remains assigned to root because the program is installed setuid root.

line 144
The audit_no_resource(S) routine also prints a message to stderr.

lines 145-146
setgid(S) is a system call that is audited automatically. If an error occurs, it is handled with the syserror routine (defined in lines 293-310) rather than an audit record.

lines 147-148
Similarly, execv(S) is also audited automatically.

loge.c (Part 7/17)

154 void 155 failed( 156 int code, /* exit(S) status */ 157 char *who, /* Name of attempting user, if known */ 158 char *argv[] /* Command attempted (with arguments) */ 159 ) { 160 if (who != (char *)0 || (who = cuserid((char *)0)) != (char *)0) 161 sulog(who, FALSE, argv); 162 exit(code); 163 /* NOTREACHED */ 164 }

165 void log_write(FILE *, char *, char *, struct tm *, int, char **); 166 FILE *log_open(char *);

167 void 168 sulog( 169 char *who, 170 int success, 171 char *argv[] 172 ) { 173 char *logf; /* Name of su logfile */ 174 char *ctty; /* Name of console */ 175 char *ttyn; /* Name of this tty */ 176 time_t now; /* Current time (secs) */ 177 struct tm at; 178 FILE *fp; 179 char *str;

180 logf = (char *)0; 181 ctty = (char *)0; 182 if (defopen(su_defaults) == 0) { 183 if ((str = defread("SULOG=")) != (char *)0) 184 logf = strdup(str); 185 if ((str = defread("CONSOLE=")) != (char *)0) 186 ctty = strdup(str); 187 defopen((char *)0); /*close the defaults file */ 188 } 189 if (logf == (char *)0 && ctty == (char *)0) 190 return;


lines 167-207
These lines define the sulog function called in line 140. This function adds an entry to the super-user log, much as the su(C) command does. The /etc/default/su file defines files in which this information should be recorded. This process does not replace auditing. Morever, the information is not recorded as reliably as in the Audit Trail; however, it is easier to use. It also ensures that the super-user log records all accesses to super-user privileges except for root login sessions at the console.

lines 180-190
These lines scan /etc/default/su for definitions of SULOG and CONSOLE. If none are found, no logging is done. The code assumes that these definitions use an absolute pathname. The su(C) command also requires that absolute pathnames be used, so this is legitimate.

lines 191-196
These lines determine a probable name for the terminal the user is logged in on. This name is not quite as reliable as the terminal name recorded in the Audit Trail, but it is adequate in most cases.

lines 197-200
These lines log this attempt in the super-user logfile.

lines 201-206
If CONSOLE is defined and the user is not at that location, log this attempt on that terminal.

lines 198, 204
The log_write function is defined in lines 209-233.

loge.c (Part 8/17)

191 if ((ttyn = ttyname(0)) == (char *)0) 192 if ((ttyn = ttyname(1)) == (char *)0) 193 if ((ttyn = ttyname(2)) == (char *)0) 194 ttyn = "/dev/tty??";

195 now = time((time_t *)0); 196 at = *localtime(&now);

197 if (logf != (char *)0 && (fp = log_open(logf)) != (FILE *)0) { 198 log_write(fp, who, ttyn, &at, success, argv); 199 (void) fclose(fp); 200 }

201 if (ctty != (char *)0 && strcmp(ctty, ttyn) != 0 && 202 (fp = fopen(ctty, "a")) != (FILE *)0 203 ) { 204 log_write(fp, who, ttyn, &at, success, argv); 205 (void) fclose(fp); 206 } 207 }

loge.c (Part 9/17)

208 void	graphic(char *, FILE *);

209 void 210 log_write( 211 FILE *fp, /* Log file (opened to append) */ 212 char *who, /* Name of user responsible */ 213 char *where, /* Location (terminal) */ 214 struct tm *when, /* Date and time */ 215 int success, /* TRUE if command will be run */ 216 char *argv[] /* Command (and arguments) run */ 217 ) { 218 char *devn; /* Basename of terminal <where> */

219 if ((devn = strrchr(where, '/')) != (char *)0) 220 devn++; 221 else 222 devn = where; 223 (void) fprintf(fp, "LOGE %.2d/%.2d %.2d:%.2d %c %s %s-root", 224 when->tm_mon+1, when->tm_mday, when->tm_hour, when->tm_min, 225 success ? '+' : '-', devn, who 226 ); 227 while (*argv != (char *)0) { 228 putc(' ', fp); 229 graphic(*argv, fp); 230 argv++; 231 } 232 putc('\n', fp); 233 }


lines 209-233
This log_write function is called in lines 198 and 204. It writes an entry to the defined log file, prefixing each entry with ``LOGE'' rather than ``SU'' to distinguish these entries from those written by the su(C) command. The entry also includes the command run and the arguments used.

line 229
Lines 234-255 define the graphic function which prints a string using all readable, printable ASCII characters.

loge.c (Part 10/17)

234 void 235 graphic( 236 char *s, 237 FILE *fp 238 ) { 239 char c;

240 while ((c = *s++) != '\0') { 241 if ( ! isascii(c)) { 242 (void) fputs("M-", fp); 243 c = toascii(c); 244 } 245 if (c == 0177) { 246 putc('^', fp); 247 c = '?'; 248 } 249 else if (iscntrl(c)) { 250 putc('^', fp); 251 c |= 0100; 252 } 253 putc(c, fp); 254 } 255 }


lines 234-255
Line 229 calls the graphic function to output a string that uses only printable characters. It assumes that the character set in use is 7-bit ASCII only. Any character that is not a printable 7-bit ASCII character is converted to a printable character. Some utilities do not convert the tab (\t), bell (\007), and newline (\n) characters, but this function does to keep the log reasonably neat. If this program were going to be run on terminals that support an alternate code set, additional character conversions would be required.

loge.c (Part 11/17)

256 char	*cfs_to_str(int);

257 FILE * 258 log_open( 259 char *logfile 260 ) { 261 int dei; /* Database Error Indication */

262 if (eaccess(logfile, F_OK)) { 263 dei = create_file_securely(logfile, AUTH_VERBOSE, 264 "record attempt to run program as superuser" 265 ); 266 if (dei != CFS_GOOD_RETURN) { 267 (void) fprintf(stderr, "%s: %s: %s", 268 command_name, cfs_to_str(dei), logfile 269 ); 270 return ((FILE *)0); 271 } 272 } 273 return (fopen(logfile, "a")); 274 }

275 struct namepair cfs_str_tab[] = { 276 "Successfully and securely created file", CFS_GOOD_RETURN, 277 "Cannot securely create new file", CFS_CAN_NOT_OPEN_FILE, 278 "File not listed in File Control database", CFS_NO_FILE_CONTROL_ENTRY, 279 "Cannot change mode on newly created file", CFS_CAN_NOT_CHG_MODE, 280 "Cannot set owner of newly created file", CFS_CAN_NOT_CHG_OWNER_GROUP, 281 (char *)0, 0 282 };

283 char * 284 cfs_to_str( 285 int code /* Return value from create_file_securely() */ 286 ) { 287 struct namepair *np;

288 for (np = cfs_str_tab; np->name != (char *)0; np++) 289 if (np->value == code) 290 return (np->name); 291 return ("Unknown problem with secure file creation"); 292 }



lines 256-274
These lines open a log file.

lines 275-292
These lines convert a create_file_securely() return value to a message.

loge.c (Part 12/17)

293 void 294 syserror( 295 int code, 296 char *fmt, 297 ... 298 ) { 299 va_list args;

300 (void) fprintf(stderr, "%s: ", command_name);

301 va_start(args, fmt); 302 (void) vfprintf(stderr, fmt, args); 303 va_end(args);

304 (void) fputs(": ", stderr); 305 if (0 < code && code < sys_nerr) 306 (void) fprintf(stderr, "%s (error %d)", sys_errlist[code], code); 307 else 308 (void) fprintf(stderr, "Unknown system error %d", code); 309 putc('\n', stderr); 310 }


lines 293-310
The syserror subroutine is used rather than the standard perror(S) routine because this allows the use of printf format strings, and perror does not.

loge.c (Part 13/17)

311 int
312 check_TCB_path(
313 	char *path,
314 	char ptype,
315 	char *desc
316 ) {
317 	int result;

318 if (check_DAC_path(path, ptype, desc)) 319 result = -1; 320 else if ((path = find_auth_file((char *)0, OT_FILE_CNTL)) == (char *)0) 321 result = -1; 322 else { 323 result = check_DAC_path(path, TCB_FILE, "File Control database"); 324 free(path); 325 } 326 return (result); 327 }


lines 311-327
The check_TCB_path subroutine and the check_DAC_path routine (defined in lines 328-384) attempt to discover integrity violations. check_TCB_path verifies a pathname of a file listed in the File Control database, which in turn checks the integrity of the File Control database itself.

lines 313-315
The subroutine takes three arguments, specifying, in turn, the full pathname of a file that is listed in the File Control Database (line 313), the file type (line 314; valid values are listed in lines 26-28), and a description of the file.

line 313
The path name is assumed to be both canonical, meaning it does not contain consecutive backslash (\\) characters, and absolute, meaning that it begins with slash (/).

line 326
check_TCB_path returns 0 if the integrity check finds no problems, and non-0 otherwise. check_TCB_path can be fooled by pathnames containing ``..''; however, this program is careful to not pass any such pathnames to this routine.

loge.c (Part 14/17)

328 int
329 check_DAC_path(
330 	char *path,
331 	char ptype,
332 	char *desc
333 ) {
334 	char c, *temp, *cp, *text, buf[ARBSTRSIZ], type;
335 	struct pr_file *prf;
336 	enum DAC_status sts;

337 if ((temp = strdup(path)) == (char *)0) { 338 audit_no_resource(path, OT_MEMORY, "cannot check pathname"); 339 return (-1); 340 }

341 cp = temp + 1; /* Assume absolute path (*temp is "/") */ 342 (void) sprintf(buf, "Path leading to %s", desc); 343 text = buf; 344 type = TCB_DIRECTORY; 345 for (;;) { 346 if (cp == (char *)0 || (c = *cp) == ' ') { 347 text = desc; 348 type = ptype; 349 } 350 else { 351 c = *cp; 352 *cp = ' '; 353 } 354 if ((prf = getprfinam(temp)) == (struct pr_file *)0) 355 sts = NotListed; 356 else if (type && prf->uflg.fg_type && *prf->ufld.fd_type != type) 357 sts = WrongDAC; 358 else 359 sts = compare_DAC_attributes(temp, prf);


lines 328-384
The check_DAC_path subroutine checks the attributes of an entire path; it checks the components of a path to see that the DAC is correct. In combination with the check_TCB_path routine (defined in lines 311-327), this routine verifies the integrity of the File Control database itself.

lines 337-340
These lines make a working copy of the pathname that can be modified.

lines 341-384
This code ``walks'' down the working pathname, verifying that each intermediate directory is indeed a directory, until the entire path is checked against the File Control database.

loge.c (Part 15/17)

360 switch (sts) { 361 case MatchesDAC: 362 case ExceedsDAC: 363 break; 364 case NotListed: 365 sa_audit_security_failure( 366 OT_FILE_CNTL, 367 (long)NotListed, (long)MatchesDAC, 368 temp, text 369 ); 370 free(temp); 371 return (-1); 372 case WrongDAC: 373 default: 374 audit_lax_file(temp, text); 375 free(temp); 376 return (-1); 377 } 378 if (cp == (char *)0 || (*cp = c) == '\0') 379 break; 380 cp = strchr(cp + 1, '/'); 381 } 382 free(temp);

383 return (0); 384 }

loge.c (Part 16/17)

385 enum DAC_status
386 compare_DAC_attributes(
387 	char *path,
388 	register struct pr_file *prf
389 ) {
390 	struct stat stbuf;
391 	mode_t f_mode, d_mode;
392 	char f_type;

393 if (prf == (struct pr_file *)0) 394 return (NotListed);

395 if (stat(path, &stbuf)) 396 return (NoSuchFile);

397 if (prf->uflg.fg_uid && prf->ufld.fd_uid != stbuf.st_uid) 398 return (WrongDAC); 399 if (prf->uflg.fg_gid && prf->ufld.fd_gid != stbuf.st_gid) 400 return (WrongDAC);

401 if (prf->uflg.fg_type) { 402 switch (stbuf.st_mode & S_IFMT) { 403 case S_IFDIR: f_type = 'd'; break; 404 case S_IFREG: f_type = 'r'; break; 405 case S_IFCHR: f_type = 'c'; break; 406 case S_IFBLK: f_type = 'b'; break; 407 #ifdef S_IFIFO 408 case S_IFIFO: f_type = 'f'; break; 409 #endif 410 #ifdef S_IFSOCK 411 case S_IFSOCK: f_type = 's'; break; 412 #endif


lines 385-431
The compare_DAC_attributes subroutine compares the File Control database to the actual disk file. The return value reports the result:

ExceedsDAC
Exiting file grants less access than required.

NoSuchFile
Disk file does not exist.

NotListed
File is not listed in File Control database.

MatchesDAC
Existing file matches the required DAC exactly.

WrongDAC
Existing file does not match the required DAC.

As a general rule, everything listed in the File Control database is part of the TCB.


lines 397-400
If the user or group of the disk file is not listed in the database, it is treated as a ``wildcard'' feature that is matched by all users or groups.

lines 401-420
If the database specifies a file type (regular, directory, and so on), compare it to the file type defined in the disk file's inode.

loge.c (Part 17/17)

413 #ifdef S_IFLNK
414 		    case S_IFLNK:	f_type = 'l';	break;
415 #endif
416 		    default:		return (WrongDAC);
417 		}
418 		if (*prf->ufld.fd_type != f_type)
419 			return (WrongDAC);
420 	}

421 f_mode = (stbuf.st_mode & ~S_IFMT); 422 if (prf->uflg.fg_mode) 423 d_mode = (prf->ufld.fd_mode & ~S_IFMT); 424 else 425 d_mode = 0; 426 if (d_mode == f_mode) 427 return (MatchesDAC); 428 else if ((~d_mode & f_mode) == 0) 429 return (ExceedsDAC);

430 return (WrongDAC); 431 }


lines 421-431
If the database lists an access mode for the file, compare it to the actual mode of the file. If the database does not list an access mode for the file, this routine assumes 000 permissions (no access at all). Note that the modes do not have to compare exactly; such things as a sticky bit or lock set against the file may modify the disk file's mode but not be reflected in the File Control database.


Footnotes

To translate a long encrypted password string into a form usable on earlier UNIX systems, it is only necessary to truncate it to the first 13 characters. Because earlier UNIX systems ignore clear-text characters following the first eight, the encryption matches. SCO UNIX system V/386, Release 3.2, Versions 4.0 and later provide a configurable parameter to allow the system's encryption mechanisms to ignore clear-text characters following the first eight. This creates complete compatibility with older systems.

The first element of the encrypted string is a two character salt. This is followed by 11 encrypted characters using that salt. The additional strings are also 11 encrypted characters, using a salt that is taken from the first two characters of the preceding 11.

Previous topic: prwarn.c example

© 2003 Caldera International, Inc. All rights reserved.
SCO OpenServer Release 5.0.7 -- 11 February 2003