1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1998, by Sun Microsystems, Inc.
3*7c478bd9Sstevel@tonic-gate  * All rights reserved.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate #include <stdio.h>
7*7c478bd9Sstevel@tonic-gate #include <string.h>
8*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
9*7c478bd9Sstevel@tonic-gate #include <unistd.h>
10*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
11*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
12*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
13*7c478bd9Sstevel@tonic-gate 
14*7c478bd9Sstevel@tonic-gate /*
15*7c478bd9Sstevel@tonic-gate  * safechown changes the owner ship of src to uid. If the mode parameter
16*7c478bd9Sstevel@tonic-gate  * does not equal -1 changes the mode of src as well.
17*7c478bd9Sstevel@tonic-gate  *
18*7c478bd9Sstevel@tonic-gate  * return -1 on failure and 0 on success.
19*7c478bd9Sstevel@tonic-gate  */
20*7c478bd9Sstevel@tonic-gate 
21*7c478bd9Sstevel@tonic-gate int
safechown(const char * src,uid_t uid,gid_t gid,int mode)22*7c478bd9Sstevel@tonic-gate safechown(const char *src, uid_t uid, gid_t gid, int mode)
23*7c478bd9Sstevel@tonic-gate {
24*7c478bd9Sstevel@tonic-gate int fd;
25*7c478bd9Sstevel@tonic-gate struct stat fdbuf;
26*7c478bd9Sstevel@tonic-gate struct stat lbuf;
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate 	if ((fd = open(src, O_RDONLY, 0)) == -1)
29*7c478bd9Sstevel@tonic-gate 		return (-1);
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate 	if (fstat(fd, &fdbuf)) {
32*7c478bd9Sstevel@tonic-gate 		close(fd);
33*7c478bd9Sstevel@tonic-gate 		return (-1);
34*7c478bd9Sstevel@tonic-gate 	}
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate 	/* Make sure non directories are not hard links */
37*7c478bd9Sstevel@tonic-gate 	if (!S_ISDIR(fdbuf.st_mode) && fdbuf.st_nlink != 1) {
38*7c478bd9Sstevel@tonic-gate 		close(fd);
39*7c478bd9Sstevel@tonic-gate 		return (-1);
40*7c478bd9Sstevel@tonic-gate 	}
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate 	if (lstat(src, &lbuf)) {
43*7c478bd9Sstevel@tonic-gate 		close(fd);
44*7c478bd9Sstevel@tonic-gate 		return (-1);
45*7c478bd9Sstevel@tonic-gate 	}
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate 	/* Make sure file is not a symlink */
48*7c478bd9Sstevel@tonic-gate 	if (fdbuf.st_ino != lbuf.st_ino || fdbuf.st_dev != lbuf.st_dev ||
49*7c478bd9Sstevel@tonic-gate 		fdbuf.st_mode != lbuf.st_mode) {
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate 		close(fd);
52*7c478bd9Sstevel@tonic-gate 		return (-1);
53*7c478bd9Sstevel@tonic-gate 	}
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate 	/* we should probably get the primary group id for uid here */
56*7c478bd9Sstevel@tonic-gate 	if (fchown(fd, uid, gid)) {
57*7c478bd9Sstevel@tonic-gate 		close(fd);
58*7c478bd9Sstevel@tonic-gate 		return (-1);
59*7c478bd9Sstevel@tonic-gate 	}
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate 	if (mode != -1) {
62*7c478bd9Sstevel@tonic-gate 		if (fchmod(fd, (mode_t)mode)) {
63*7c478bd9Sstevel@tonic-gate 		    close(fd);
64*7c478bd9Sstevel@tonic-gate 		    return (-1);
65*7c478bd9Sstevel@tonic-gate 		}
66*7c478bd9Sstevel@tonic-gate 	}
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 	close(fd);
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 	return (0);
71*7c478bd9Sstevel@tonic-gate }
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate #ifdef TEST
74*7c478bd9Sstevel@tonic-gate void
usage(char * prg)75*7c478bd9Sstevel@tonic-gate usage(char *prg)
76*7c478bd9Sstevel@tonic-gate {
77*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "Usage %s [-u uid] [-m mode] source\n", prg);
78*7c478bd9Sstevel@tonic-gate 	exit(1);
79*7c478bd9Sstevel@tonic-gate }
80*7c478bd9Sstevel@tonic-gate 
main(int argc,char * argv[])81*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
82*7c478bd9Sstevel@tonic-gate {
83*7c478bd9Sstevel@tonic-gate 	int opt;
84*7c478bd9Sstevel@tonic-gate 	int mode = -1;
85*7c478bd9Sstevel@tonic-gate 	uid_t uid = 0;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "m:u:")) != EOF) {
88*7c478bd9Sstevel@tonic-gate 		switch (opt) {
89*7c478bd9Sstevel@tonic-gate 		case 'm':
90*7c478bd9Sstevel@tonic-gate 			mode = strtol(optarg, 0, 8);
91*7c478bd9Sstevel@tonic-gate 			break;
92*7c478bd9Sstevel@tonic-gate 		case 'u':
93*7c478bd9Sstevel@tonic-gate 			uid = atoi(optarg);
94*7c478bd9Sstevel@tonic-gate 			break;
95*7c478bd9Sstevel@tonic-gate 		default:
96*7c478bd9Sstevel@tonic-gate 			usage(argv[0]);
97*7c478bd9Sstevel@tonic-gate 	}
98*7c478bd9Sstevel@tonic-gate }
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate     if (argc - optind != 1)
101*7c478bd9Sstevel@tonic-gate 	usage(argv[0]);
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate     if (safechown(argv[optind], uid, getgid(), mode)) {
104*7c478bd9Sstevel@tonic-gate 	perror("safechown");
105*7c478bd9Sstevel@tonic-gate 	exit(1);
106*7c478bd9Sstevel@tonic-gate     }
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate     return (0);
109*7c478bd9Sstevel@tonic-gate }
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate #endif  /* TEST */
112