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