71595de3cb71a4245e2beaa0e663509373937035
[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 #include <string.h>
39 #include <ctype.h>
40
41 #include <rx/xdr.h>
42 #include <rx/rx.h>
43 #include <stdio.h>
44 #include <afs/afsutil.h>
45 #include <afs/fileutil.h>
46
47 #ifdef AFS_ATHENA_STDENV
48 #include <krb.h>
49 #endif
50
51 #include "auth.h"
52 #include "cellconfig.h"
53 #include "keys.h"
54 #include "afs/audit.h"
55
56
57 #if !defined(UKERNEL)
58 int afsconf_CheckAuth(adir, acall)
59 register struct rx_call *acall;
60 register struct afsconf_dir *adir; {
61     LOCK_GLOBAL_MUTEX
62     return ((afsconf_SuperUser(adir, acall, (char *)0) == 0)? 10029 : 0);
63     UNLOCK_GLOBAL_MUTEX
64 }
65 #endif /* !defined(UKERNEL) */
66
67 static GetNoAuthFlag(adir)
68 struct afsconf_dir *adir; {
69     if (access(AFSDIR_SERVER_NOAUTH_FILEPATH, 0) == 0) {
70         osi_audit ( NoAuthEvent, 0, AUD_END ); /* some random server is running noauth */
71         return 1;   /* if /usr/afs/local/NoAuth file exists, allow access */
72       }
73     return 0;
74 }
75
76
77 afsconf_GetNoAuthFlag(adir)
78 struct afsconf_dir *adir; {
79     int rc;
80
81     LOCK_GLOBAL_MUTEX
82     rc = GetNoAuthFlag(adir);
83     UNLOCK_GLOBAL_MUTEX
84     return rc;
85 }
86
87 afsconf_SetNoAuthFlag(adir, aflag)
88 struct afsconf_dir *adir;
89 int aflag; {
90     register afs_int32 code;
91     
92     LOCK_GLOBAL_MUTEX
93
94     if (aflag == 0) {
95         /* turn off noauth flag */
96         code = ( unlink(AFSDIR_SERVER_NOAUTH_FILEPATH) ? errno : 0 );
97         osi_audit ( NoAuthDisableEvent, code, AUD_END ); 
98     }
99     else {
100         /* try to create file */
101         code = open(AFSDIR_SERVER_NOAUTH_FILEPATH, O_CREAT | O_TRUNC | O_RDWR, 0666);
102         if (code >= 0) { 
103           close(code);
104           osi_audit ( NoAuthEnableEvent, 0, AUD_END ); 
105         }
106         else 
107           osi_audit ( NoAuthEnableEvent, errno, AUD_END ); 
108     }
109     UNLOCK_GLOBAL_MUTEX
110 }
111
112 /* deletes a user from the UserList file */
113 afsconf_DeleteUser(adir, auser)
114 struct afsconf_dir *adir;
115 register char *auser; {
116     char tbuffer[1024];
117     char nbuffer[1024];
118     register FILE *tf;
119     register FILE *nf;
120     register int flag;
121     char tname[64];
122     char *tp;
123     int found;
124     struct stat tstat;
125     register afs_int32 code;
126
127     LOCK_GLOBAL_MUTEX
128     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
129 #ifndef AFS_NT40_ENV
130     {
131         /*
132          * We attempt to fully resolve this pathname, so that the rename
133          * of the temporary file will work even if UserList is a symlink
134          * into a different filesystem.
135          */
136         char resolved_path[1024];
137
138         if (realpath(tbuffer, resolved_path)) {
139             strcpy(tbuffer, resolved_path);
140         }
141     }
142 #endif /* AFS_NT40_ENV */
143     tf = fopen(tbuffer, "r");
144     if (!tf) {
145         UNLOCK_GLOBAL_MUTEX
146         return -1;
147     }
148     code = stat(tbuffer, &tstat);
149     if (code < 0) {
150         UNLOCK_GLOBAL_MUTEX
151         return code;
152     }
153     strcpy(nbuffer, tbuffer);
154     strcat(nbuffer, ".NXX");
155     nf = fopen(nbuffer, "w+");
156     if (!nf) {
157         fclose(tf);
158         UNLOCK_GLOBAL_MUTEX
159         return EIO;
160     }
161     flag = 0;
162     found = 0;
163     while (1) {
164         /* check for our user id */
165         tp = fgets(nbuffer, sizeof(nbuffer), tf);
166         if (tp == (char *)0) break;
167         code = sscanf(nbuffer, "%64s", tname);
168         if (code == 1 && strcmp(tname, auser) == 0) {
169             /* found the guy, don't copy to output file */
170             found = 1;
171         }
172         else {
173             /* otherwise copy original line  to output */
174             fprintf(nf, "%s", nbuffer);
175         }
176     }
177     fclose(tf);
178     if (ferror(nf)) flag = 1;
179     if (fclose(nf) == EOF) flag = 1;
180     strcpy(nbuffer, tbuffer);
181     strcat(nbuffer, ".NXX");    /* generate new file name again */
182     if (flag == 0) {
183         /* try the rename */
184         flag = renamefile(nbuffer, tbuffer);
185         if (flag == 0)
186             flag = chmod(tbuffer, tstat.st_mode);
187     }
188     else unlink(nbuffer);
189
190     /* finally, decide what to return to the caller */
191     UNLOCK_GLOBAL_MUTEX
192     if (flag) return EIO;       /* something mysterious went wrong */
193     if (!found) return ENOENT;  /* entry wasn't found, no changes made */
194     return 0;                   /* everything was fine */
195 }
196
197 /* returns nth super user from the UserList file */
198 afsconf_GetNthUser(adir, an, abuffer, abufferLen)
199 struct afsconf_dir *adir;
200 afs_int32 an;
201 char *abuffer;
202 afs_int32 abufferLen; {
203     char tbuffer[256];
204     register FILE *tf;
205     char tname[64];
206     register char *tp;
207     register int flag;
208     register afs_int32 code;
209
210     LOCK_GLOBAL_MUTEX
211     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
212     tf = fopen(tbuffer, "r");
213     if (!tf) {
214         UNLOCK_GLOBAL_MUTEX
215         return 1;
216     }
217     flag = 1;
218     while (1) {
219         /* check for our user id */
220         tp = fgets(tbuffer, sizeof(tbuffer), tf);
221         if (tp == (char *)0) break;
222         code = sscanf(tbuffer, "%64s", tname);
223         if (code == 1 && an-- == 0) {
224             flag = 0;
225             break;
226         }
227     }
228     if (flag == 0) strcpy(abuffer, tname);
229     fclose(tf);
230     UNLOCK_GLOBAL_MUTEX
231     return flag;
232 }
233
234 /* returns true iff user is in the UserList file */
235 static FindUser(adir, auser)
236 struct afsconf_dir *adir;
237 register char *auser; {
238     char tbuffer[256];
239     register bufio_p bp;
240     char tname[64];
241     register char *tp;
242     register int flag;
243     register afs_int32 code;
244     int rc;
245
246     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
247     bp = BufioOpen(tbuffer, O_RDONLY, 0);
248     if (!bp) return 0;
249     flag = 0;
250     while (1) {
251         /* check for our user id */
252         rc = BufioGets(bp, tbuffer, sizeof(tbuffer));
253         if (rc < 0) break;
254         code = sscanf(tbuffer, "%64s", tname);
255         if (code == 1 && strcmp(tname, auser) == 0) {
256             flag = 1;
257             break;
258         }
259     }
260     BufioClose(bp);
261     return flag;
262 }
263
264 /* add a user to the user list, checking for duplicates */
265 afsconf_AddUser(adir, aname)
266 struct afsconf_dir *adir;
267 char *aname; {
268     FILE *tf;
269     register afs_int32 code;
270     char tbuffer[256];
271
272     LOCK_GLOBAL_MUTEX
273     if (FindUser(adir, aname)) {
274         UNLOCK_GLOBAL_MUTEX
275         return EEXIST;  /* already in the list */
276     }
277
278     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
279     tf = fopen(tbuffer, "a+");
280     if (!tf) {
281         UNLOCK_GLOBAL_MUTEX
282         return EIO;
283     }
284     fprintf(tf, "%s\n", aname);
285     code = 0;
286     if (ferror(tf)) code = EIO;
287     if (fclose(tf)) code = EIO;
288     UNLOCK_GLOBAL_MUTEX
289     return code;
290 }
291
292 /* special CompFindUser routine that builds up a princ and then
293         calls finduser on it. If found, returns char * to user string, 
294         otherwise returns NULL. The resulting string should be immediately
295         copied to other storage prior to release of mutex. */
296 static char *CompFindUser(adir, name, sep, inst, realm)
297     struct afsconf_dir *adir;
298     char *name;
299     char *sep;
300     char *inst;
301     char *realm;
302 {
303     static char fullname[ MAXKTCNAMELEN + MAXKTCNAMELEN +
304         MAXKTCREALMLEN + 3 ];
305
306     /* always must have name */
307     if ( !name || !name[0] ) { return NULL; }
308     strcpy(fullname, name);
309
310     /* might have instance */
311     if ( inst && inst[0] ) {
312         if ( !sep || !sep[0] ) { return NULL; }
313
314         strcat(fullname, sep);
315         strcat(fullname, inst);
316     }
317
318     /* might have realm */
319     if ( realm && realm[0] )
320     {
321         strcat(fullname, "@");
322         strcat(fullname, realm);
323     }
324
325     if ( FindUser(adir, fullname) ) {
326         return fullname;
327     } else {
328         return NULL;
329     }
330 }
331
332
333 /* make sure user authenticated on rx call acall is in list of valid
334     users. Copy the "real name" of the authenticated user into namep
335     if a pointer is passed.
336 */
337 afs_int32 afsconf_SuperUser(adir, acall, namep)
338 struct afsconf_dir *adir;
339 struct rx_call *acall;
340 char *namep; {
341     register struct rx_connection *tconn;
342     register afs_int32 code;
343     int flag;
344
345     LOCK_GLOBAL_MUTEX
346     if (!adir) {
347         UNLOCK_GLOBAL_MUTEX
348         return 0;
349     }
350
351     if (afsconf_GetNoAuthFlag(adir)) {
352         if (namep) strcpy(namep, "<NoAuth>");
353         UNLOCK_GLOBAL_MUTEX
354         return 1;
355     }
356
357     tconn = rx_ConnectionOf(acall);
358     code = rx_SecurityClassOf(tconn);
359     if (code == 0) {
360         UNLOCK_GLOBAL_MUTEX
361         return 0;           /* not authenticated at all, answer is no */
362     }
363     else if (code == 1) {
364         /* bcrypt tokens */
365         UNLOCK_GLOBAL_MUTEX
366         return 0;                       /* not supported any longer */
367     }
368     else if (code == 2) {
369         char tname[MAXKTCNAMELEN];      /* authentication from ticket */
370         char tinst[MAXKTCNAMELEN];
371         char tcell[MAXKTCREALMLEN];
372         char tcell_l[MAXKTCREALMLEN];
373         char *tmp;
374         
375         /* keep track of which one actually authorized request */
376         char uname[MAXKTCNAMELEN+MAXKTCNAMELEN+MAXKTCREALMLEN+3];
377
378         afs_uint32 exp;
379         static char lcell[MAXCELLCHARS] = "";
380         static char lrealm[AFS_REALM_SZ] = "";
381         
382         /* get auth details from server connection */
383         code = rxkad_GetServerInfo
384             (acall->conn, (afs_int32 *) 0, &exp, 
385                 tname, tinst, tcell, (afs_int32 *) 0);
386         if (code) {
387             UNLOCK_GLOBAL_MUTEX
388             return 0; /* bogus connection/other error */
389         }
390
391         /* don't bother checking anything else if tix have expired */
392 #ifdef AFS_PTHREAD_ENV
393         if (exp < clock_Sec()) {
394 #else
395         if (exp < FT_ApproxTime()) {
396 #endif
397             UNLOCK_GLOBAL_MUTEX
398             return 0;   /* expired tix */
399         }
400
401         /* generate lowercased version of cell name */
402         strcpy(tcell_l, tcell);
403         tmp = tcell_l;
404         while ( *tmp ) { *tmp = tolower(*tmp); *tmp++; }
405
406         /* determine local cell name. It's static, so will only get
407            calculated the first time through */
408         if (!lcell[0])
409             afsconf_GetLocalCell(adir, lcell, sizeof(lcell));
410
411         /* if running a krb environment, also get the local realm */
412         /* note - this assumes AFS_REALM_SZ <= MAXCELLCHARS */
413         /* just set it to lcell if it fails */
414         if (!lrealm[0]) {
415             if (afs_krb_get_lrealm(lrealm, 0) != 0) /* KSUCCESS */
416                 strncpy(lrealm, lcell, AFS_REALM_SZ);
417         }
418
419
420         /* start with no uname and no authorization */
421         strcpy(uname, "");
422         flag = 0;
423
424         /* localauth special case */
425         if ( strlen(tinst) == 0 && strlen(tcell) == 0 && 
426                 !strcmp(tname, AUTH_SUPERUSER) ) {
427             strcpy(uname, "<LocalAuth>");
428             flag = 1;
429
430         /* cell of connection matches local cell or krb4 realm */
431         } else if ( !strcasecmp(tcell, lcell) || !strcasecmp(tcell,lrealm) ) {
432             if ( (tmp = CompFindUser(adir, tname, ".", tinst, NULL)) ) {
433                 strcpy(uname, tmp);
434                 flag = 1;
435 #ifdef notyet
436             } else if ( (tmp = CompFindUser(adir, tname, "/", tinst, NULL)) ) {
437                 strcpy(uname, tmp);
438                 flag = 1;
439 #endif
440             }
441
442         /* cell of conn doesn't match local cell or realm */
443         } else {
444             if ( (tmp = CompFindUser(adir, tname, ".", tinst, tcell)) ) {
445                 strcpy(uname, tmp);
446                 flag = 1;
447 #ifdef notyet
448             } else if ( (tmp = CompFindUser(adir, tname, "/", tinst, tcell)) ) {
449                 strcpy(uname, tmp);
450                 flag = 1;
451 #endif
452             } else if ( (tmp = CompFindUser(adir, tname, ".", tinst, tcell_l)) ) {
453                 strcpy(uname, tmp);
454                 flag = 1;
455 #ifdef notyet
456             } else if ( (tmp = CompFindUser(adir, tname, "/", tinst, tcell_l)) ) {
457                 strcpy(uname, tmp);
458                 flag = 1;
459 #endif
460             }
461         }
462
463         if (namep)
464             strcpy(namep, uname);
465         UNLOCK_GLOBAL_MUTEX
466         return flag;
467     }
468     else { /* some other auth type */
469         UNLOCK_GLOBAL_MUTEX
470         return  0;          /* mysterious, just say no */
471     }
472 }