eliminate-libaudit-requirement-20001104
[openafs.git] / src / auth / userok.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  * Revision 2.3  91/08/09  18:10:56
12  * added a new param to afsconf_SuperUser
13  * 
14  * Revision 2.2  90/08/29  15:10:43
15  * Cleanups.
16  * Reject security index #1: rxvab/bcrypt.
17  * 
18  * Revision 2.1  90/08/07  18:52:21
19  * Start with clean version to sync test and dev trees.
20  * */
21
22 #include <afs/param.h>
23 #include <afs/stds.h>
24 #include <afs/pthread_glock.h>
25 #include <sys/types.h>
26 #ifdef AFS_NT40_ENV
27 #include <winsock2.h>
28 #include <fcntl.h>
29 #include <io.h>
30 #else
31 #include <sys/file.h>
32 #include <netinet/in.h>
33 #include <netdb.h>
34 #endif
35 #include <sys/stat.h>
36 #include <stdlib.h>     /* for realpath() */
37 #include <errno.h>
38
39 #include <rx/xdr.h>
40 #include <rx/rx.h>
41 #include <stdio.h>
42 #include <afs/afsutil.h>
43 #include <afs/fileutil.h>
44
45 #ifdef AFS_ATHENA_STDENV
46 #include <krb.h>
47 #endif
48
49 #include "auth.h"
50 #include "cellconfig.h"
51 #include "keys.h"
52 #include "afs/audit.h"
53
54
55 #if !defined(UKERNEL)
56 int afsconf_CheckAuth(adir, acall)
57 register struct rx_call *acall;
58 register struct afsconf_dir *adir; {
59     LOCK_GLOBAL_MUTEX
60     return ((afsconf_SuperUser(adir, acall, (char *)0) == 0)? 10029 : 0);
61     UNLOCK_GLOBAL_MUTEX
62 }
63 #endif /* !defined(UKERNEL) */
64
65 static GetNoAuthFlag(adir)
66 struct afsconf_dir *adir; {
67     if (access(AFSDIR_SERVER_NOAUTH_FILEPATH, 0) == 0) {
68         osi_audit ( NoAuthEvent, 0, AUD_END ); /* some random server is running noauth */
69         return 1;   /* if /usr/afs/local/NoAuth file exists, allow access */
70       }
71     return 0;
72 }
73
74
75 afsconf_GetNoAuthFlag(adir)
76 struct afsconf_dir *adir; {
77     int rc;
78
79     LOCK_GLOBAL_MUTEX
80     rc = GetNoAuthFlag(adir);
81     UNLOCK_GLOBAL_MUTEX
82     return rc;
83 }
84
85 afsconf_SetNoAuthFlag(adir, aflag)
86 struct afsconf_dir *adir;
87 int aflag; {
88     register afs_int32 code;
89     
90     LOCK_GLOBAL_MUTEX
91
92     if (aflag == 0) {
93         /* turn off noauth flag */
94         code = ( unlink(AFSDIR_SERVER_NOAUTH_FILEPATH) ? errno : 0 );
95         osi_audit ( NoAuthDisableEvent, code, AUD_END ); 
96     }
97     else {
98         /* try to create file */
99         code = open(AFSDIR_SERVER_NOAUTH_FILEPATH, O_CREAT | O_TRUNC | O_RDWR, 0666);
100         if (code >= 0) { 
101           close(code);
102           osi_audit ( NoAuthEnableEvent, 0, AUD_END ); 
103         }
104         else 
105           osi_audit ( NoAuthEnableEvent, errno, AUD_END ); 
106     }
107     UNLOCK_GLOBAL_MUTEX
108 }
109
110 /* deletes a user from the UserList file */
111 afsconf_DeleteUser(adir, auser)
112 struct afsconf_dir *adir;
113 register char *auser; {
114     char tbuffer[1024];
115     char nbuffer[1024];
116     register FILE *tf;
117     register FILE *nf;
118     register int flag;
119     char tname[64];
120     char *tp;
121     int found;
122     struct stat tstat;
123     register afs_int32 code;
124
125     LOCK_GLOBAL_MUTEX
126     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
127 #ifndef AFS_NT40_ENV
128     {
129         /*
130          * We attempt to fully resolve this pathname, so that the rename
131          * of the temporary file will work even if UserList is a symlink
132          * into a different filesystem.
133          */
134         char resolved_path[1024];
135
136         if (realpath(tbuffer, resolved_path)) {
137             strcpy(tbuffer, resolved_path);
138         }
139     }
140 #endif /* AFS_NT40_ENV */
141     tf = fopen(tbuffer, "r");
142     if (!tf) {
143         UNLOCK_GLOBAL_MUTEX
144         return -1;
145     }
146     code = stat(tbuffer, &tstat);
147     if (code < 0) {
148         UNLOCK_GLOBAL_MUTEX
149         return code;
150     }
151     strcpy(nbuffer, tbuffer);
152     strcat(nbuffer, ".NXX");
153     nf = fopen(nbuffer, "w+");
154     if (!nf) {
155         fclose(tf);
156         UNLOCK_GLOBAL_MUTEX
157         return EIO;
158     }
159     flag = 0;
160     found = 0;
161     while (1) {
162         /* check for our user id */
163         tp = fgets(nbuffer, sizeof(nbuffer), tf);
164         if (tp == (char *)0) break;
165         code = sscanf(nbuffer, "%64s", tname);
166         if (code == 1 && strcmp(tname, auser) == 0) {
167             /* found the guy, don't copy to output file */
168             found = 1;
169         }
170         else {
171             /* otherwise copy original line  to output */
172             fprintf(nf, "%s", nbuffer);
173         }
174     }
175     fclose(tf);
176     if (ferror(nf)) flag = 1;
177     if (fclose(nf) == EOF) flag = 1;
178     strcpy(nbuffer, tbuffer);
179     strcat(nbuffer, ".NXX");    /* generate new file name again */
180     if (flag == 0) {
181         /* try the rename */
182         flag = renamefile(nbuffer, tbuffer);
183         if (flag == 0)
184             flag = chmod(tbuffer, tstat.st_mode);
185     }
186     else unlink(nbuffer);
187
188     /* finally, decide what to return to the caller */
189     UNLOCK_GLOBAL_MUTEX
190     if (flag) return EIO;       /* something mysterious went wrong */
191     if (!found) return ENOENT;  /* entry wasn't found, no changes made */
192     return 0;                   /* everything was fine */
193 }
194
195 /* returns nth super user from the UserList file */
196 afsconf_GetNthUser(adir, an, abuffer, abufferLen)
197 struct afsconf_dir *adir;
198 afs_int32 an;
199 char *abuffer;
200 afs_int32 abufferLen; {
201     char tbuffer[256];
202     register FILE *tf;
203     char tname[64];
204     register char *tp;
205     register int flag;
206     register afs_int32 code;
207
208     LOCK_GLOBAL_MUTEX
209     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
210     tf = fopen(tbuffer, "r");
211     if (!tf) {
212         UNLOCK_GLOBAL_MUTEX
213         return 1;
214     }
215     flag = 1;
216     while (1) {
217         /* check for our user id */
218         tp = fgets(tbuffer, sizeof(tbuffer), tf);
219         if (tp == (char *)0) break;
220         code = sscanf(tbuffer, "%64s", tname);
221         if (code == 1 && an-- == 0) {
222             flag = 0;
223             break;
224         }
225     }
226     if (flag == 0) strcpy(abuffer, tname);
227     fclose(tf);
228     UNLOCK_GLOBAL_MUTEX
229     return flag;
230 }
231
232 /* returns true iff user is in the UserList file */
233 static FindUser(adir, auser)
234 struct afsconf_dir *adir;
235 register char *auser; {
236     char tbuffer[256];
237     register bufio_p bp;
238     char tname[64];
239     register char *tp;
240     register int flag;
241     register afs_int32 code;
242     int rc;
243
244     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
245     bp = BufioOpen(tbuffer, O_RDONLY, 0);
246     if (!bp) return 0;
247     flag = 0;
248     while (1) {
249         /* check for our user id */
250         rc = BufioGets(bp, tbuffer, sizeof(tbuffer));
251         if (rc < 0) break;
252         code = sscanf(tbuffer, "%64s", tname);
253         if (code == 1 && strcmp(tname, auser) == 0) {
254             flag = 1;
255             break;
256         }
257     }
258     BufioClose(bp);
259     return flag;
260 }
261
262 /* add a user to the user list, checking for duplicates */
263 afsconf_AddUser(adir, aname)
264 struct afsconf_dir *adir;
265 char *aname; {
266     FILE *tf;
267     register afs_int32 code;
268     char tbuffer[256];
269
270     LOCK_GLOBAL_MUTEX
271     if (FindUser(adir, aname)) {
272         UNLOCK_GLOBAL_MUTEX
273         return EEXIST;  /* already in the list */
274     }
275
276     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
277     tf = fopen(tbuffer, "a+");
278     if (!tf) {
279         UNLOCK_GLOBAL_MUTEX
280         return EIO;
281     }
282     fprintf(tf, "%s\n", aname);
283     code = 0;
284     if (ferror(tf)) code = EIO;
285     if (fclose(tf)) code = EIO;
286     UNLOCK_GLOBAL_MUTEX
287     return code;
288 }
289
290 /* make sure user authenticated on rx call acall is in list of valid
291     users.
292 */
293 afsconf_SuperUser(adir, acall, namep)
294 struct afsconf_dir *adir;
295 struct rx_call *acall;
296 char *namep; {
297     register struct rx_connection *tconn;
298     register afs_int32 code;
299     int flag;
300
301     LOCK_GLOBAL_MUTEX
302     if (!adir) {
303         UNLOCK_GLOBAL_MUTEX
304         return 0;
305     }
306     if (afsconf_GetNoAuthFlag(adir)) {
307         if (namep) strcpy(namep, "<noauth>");
308         UNLOCK_GLOBAL_MUTEX
309         return 1;
310     }
311     tconn = rx_ConnectionOf(acall);
312     code = rx_SecurityClassOf(tconn);
313     if (code == 0) {
314         UNLOCK_GLOBAL_MUTEX
315         return 0;           /* not authenticated at all, answer is no */
316     }
317     else if (code == 1) {
318         /* bcrypt tokens */
319         UNLOCK_GLOBAL_MUTEX
320         return 0;                       /* not supported any longer */
321     }
322     else if (code == 2) {
323         char tname[MAXKTCNAMELEN];      /* authentication from ticket */
324         char tinst[MAXKTCNAMELEN];
325         char tcell[MAXKTCREALMLEN];
326         char uname[MAXKTCNAMELEN];      /* name.instance */
327         int  ilen;                      /* length of instance */
328         afs_uint32 exp;
329         static char localcellname[MAXCELLCHARS] = "";
330 #if     defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
331         static char local_realm[AFS_REALM_SZ] = "";
332 #endif
333         
334         /* des tokens */
335         code = rxkad_GetServerInfo
336             (acall->conn, (afs_int32 *) 0, &exp, tname, tinst, tcell, (afs_int32 *) 0);
337         if (code) {
338             UNLOCK_GLOBAL_MUTEX
339             return 0; /* bogus */
340         }
341
342         if (strlen (tcell)) {
343             if (!localcellname[0])
344                 afsconf_GetLocalCell
345                     (adir, localcellname, sizeof(localcellname));
346 #if     defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
347             if (!local_realm[0]) {
348                 if (afs_krb_get_lrealm(local_realm, 0) != 0/*KSUCCESS*/)
349                     strncpy(local_realm, localcellname, AFS_REALM_SZ);
350             }
351             if (strcasecmp(local_realm, tcell) &&
352                (strcasecmp(localcellname, tcell)))
353 #else
354             if (strcasecmp(localcellname, tcell))
355 #endif
356                 {
357                     UNLOCK_GLOBAL_MUTEX
358                     return 0;
359                 }
360         }
361         ilen = strlen(tinst);
362         strncpy (uname, tname, sizeof(uname));
363         if (ilen) {
364             if (strlen(uname) + 1 + ilen >= sizeof(uname)) {
365                 UNLOCK_GLOBAL_MUTEX
366                 return 0;
367             }
368             strcat (uname, ".");
369             strcat (uname, tinst);
370         }
371
372 #ifdef AFS_PTHREAD_ENV
373         if (exp < clock_Sec()) {
374 #else
375         if (exp < FT_ApproxTime()) {
376 #endif
377             UNLOCK_GLOBAL_MUTEX
378             return 0;   /* expired tix */
379         }
380         if (strcmp(AUTH_SUPERUSER, uname) == 0) flag = 1;
381         else flag = FindUser(adir, uname);      /* true iff in userlist file */
382         if (namep)
383             strcpy(namep, uname);
384         UNLOCK_GLOBAL_MUTEX
385         return flag;
386     }
387     else {
388         UNLOCK_GLOBAL_MUTEX
389         return  0;          /* mysterious, just say no */
390     }
391 }