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
safechown(const char * src,uid_t uid,gid_t gid,int mode)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
usage(char * prg)77 usage(char *prg)
78 {
79 fprintf(stderr, "Usage %s [-u uid] [-m mode] source\n", prg);
80 exit(1);
81 }
82
main(int argc,char * argv[])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