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