13f66b223f1a2bac43b90f92f0d908671671c348
[openafs.git] / src / kopenafs / kopenafs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Glue code for the kopenafs API.  Mostly just wrappers around the functions
12  * included in the libsys code.
13  */
14
15 #include <errno.h>
16 #include <netinet/in.h>
17 #include <signal.h>
18 #include <stdlib.h>
19 #ifdef AFS_AIX51_ENV
20 # include <sys/cred.h>
21 # ifdef HAVE_SYS_PAG_H
22 #  include <sys/pag.h>
23 # endif
24 #endif
25 #include <sys/param.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 #include <afsconfig.h>
30 #include <afs/afssyscalls.h>
31 #include <afs/param.h>
32 #include <kopenafs.h>
33
34 static volatile sig_atomic_t syscall_okay = 1;
35
36 /* Signal handler to catch failed system calls and change the okay flag. */
37 #ifdef SIGSYS
38 static RETSIGTYPE
39 sigsys_handler(int s)
40 {
41     syscall_okay = 0;
42     signal(SIGSYS, sigsys_handler);
43 }
44 #endif /* SIGSYS */
45
46 int
47 k_hasafs(void)
48 {
49     struct ViceIoctl iob;
50     int okay, saved_errno;
51     RETSIGTYPE (*saved_func)(int);
52
53     saved_errno = errno;
54
55 #ifdef SIGSYS
56     saved_func = signal(SIGSYS, sigsys_handler);
57 #endif
58
59     iob.in = NULL;
60     iob.in_size = 0;
61     iob.out = NULL;
62     iob.out_size = 0;
63     lpioctl(NULL, VIOCSETTOK, &iob, 0);
64
65 #ifdef SIGSYS
66     signal(SIGSYS, saved_func);
67 #endif
68
69     okay = 1;
70     if (!syscall_okay || errno != EINVAL)
71         okay = 0;
72     errno = saved_errno;
73     return okay;
74 }
75
76 int
77 k_setpag(void)
78 {
79     return lsetpag();
80 }
81
82 int
83 k_pioctl(char *path, int cmd, struct ViceIoctl *cmarg, int follow)
84 {
85     return lpioctl(path, cmd, cmarg, follow);
86 }
87
88 int
89 k_unlog(void)
90 {
91     struct ViceIoctl iob;
92
93     iob.in = NULL;
94     iob.in_size = 0;
95     iob.out = NULL;
96     iob.out_size = 0;
97     return lpioctl(NULL, VIOCUNLOG, &iob, 0);
98 }
99
100
101 /*
102  * If we don't have the VIOC_GETPAG pioctl, we try to determine whether we're
103  * in a PAG by using either a special OS call (AIX 5.2 and later) or by
104  * walking the group list, which works differently for current versions of
105  * Linux.
106  *
107  * These OS differences are encapsulated in the following OS-specific haspag
108  * helper functions.
109  *
110  * This is largely copied from auth/ktc.c and should be merged with that
111  * version, but that version calls through the pioctl() interface right now
112  * and therefore pulls in Rx for NFS translator support.  This avoids an Rx
113  * dependency in the standalone libkopenafs interface.
114  */
115 #if defined(AFS_AIX52_ENV)
116 static int
117 os_haspag(void)
118 {
119     return (getpagvalue("afs") < 0) ? 0 : 1;
120 }
121 #elif defined(AFS_AIX51_ENV)
122 static int
123 os_haspag(void)
124 {
125     return 0;
126 }
127 #else
128 static int
129 os_haspag(void)
130 {
131     int ngroups;
132     gid_t *groups;
133     afs_uint32 g0, g1;
134     afs_uint32 h, l, pag;
135 # ifdef AFS_LINUX26_ENV
136     int i;
137 # endif
138
139     ngroups = getgroups(0, NULL);
140     groups = malloc(sizeof(*groups) * ngroups);
141     if (groups == NULL)
142         return 0;
143     ngroups = getgroups(ngroups, groups);
144
145     /* Check for AFS_LINUX26_ONEGROUP_ENV PAGs. */
146 # ifdef AFS_LINUX26_ENV
147     for (i = 0; i < ngroups; i++)
148         if (((groups[i] >> 24) & 0xff) == 'A') {
149             free(groups);
150             return 1;
151         }
152 # endif
153
154     /* Check for the PAG group pair. */
155     if (ngroups < 2) {
156         free(groups);
157         return 0;
158     }
159     g0 = groups[0] & 0xffff;
160     g1 = groups[1] & 0xffff;
161     free(groups);
162     g0 -= 0x3f00;
163     g1 -= 0x3f00;
164     if (g0 < 0xc000 && g1 < 0xc000) {
165         l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
166         h = (g0 >> 14);
167         h = (g1 >> 14) + h + h + h;
168         pag = ((h << 28) | l);
169         if (((pag >> 24) & 0xff) == 'A')
170             return 1;
171         else
172             return 0;
173     }
174     return 0;
175 }
176 #endif /* !AFS_AIX51_ENV */
177
178 int
179 k_haspag(void)
180 {
181     int code;
182     struct ViceIoctl iob;
183     afs_uint32 pag;
184
185     iob.in = NULL;
186     iob.in_size = 0;
187     iob.out = (caddr_t) &pag;
188     iob.out_size = sizeof(afs_uint32);
189     code = lpioctl(NULL, VIOC_GETPAG, &iob, 0);
190     if (code == 0)
191         return pag != (afs_uint32) -1;
192     else
193         return os_haspag();
194 }