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