7094daa1580cba4f877ef644a533cf486e7bfb75
[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, (char *)0) == 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 == (char *)0) 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 == (char *)0) 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 char *tp;
235     register int flag;
236     register afs_int32 code;
237     int rc;
238
239     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
240     bp = BufioOpen(tbuffer, O_RDONLY, 0);
241     if (!bp) return 0;
242     flag = 0;
243     while (1) {
244         /* check for our user id */
245         rc = BufioGets(bp, tbuffer, sizeof(tbuffer));
246         if (rc < 0) break;
247         code = sscanf(tbuffer, "%64s", tname);
248         if (code == 1 && strcmp(tname, auser) == 0) {
249             flag = 1;
250             break;
251         }
252     }
253     BufioClose(bp);
254     return flag;
255 }
256
257 /* add a user to the user list, checking for duplicates */
258 afsconf_AddUser(adir, aname)
259 struct afsconf_dir *adir;
260 char *aname; {
261     FILE *tf;
262     register afs_int32 code;
263     char tbuffer[256];
264
265     LOCK_GLOBAL_MUTEX
266     if (FindUser(adir, aname)) {
267         UNLOCK_GLOBAL_MUTEX
268         return EEXIST;  /* already in the list */
269     }
270
271     strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE, NULL);
272     tf = fopen(tbuffer, "a+");
273     if (!tf) {
274         UNLOCK_GLOBAL_MUTEX
275         return EIO;
276     }
277     fprintf(tf, "%s\n", aname);
278     code = 0;
279     if (ferror(tf)) code = EIO;
280     if (fclose(tf)) code = EIO;
281     UNLOCK_GLOBAL_MUTEX
282     return code;
283 }
284
285 /* special CompFindUser routine that builds up a princ and then
286         calls finduser on it. If found, returns char * to user string, 
287         otherwise returns NULL. The resulting string should be immediately
288         copied to other storage prior to release of mutex. */
289 static char *CompFindUser(adir, name, sep, inst, realm)
290     struct afsconf_dir *adir;
291     char *name;
292     char *sep;
293     char *inst;
294     char *realm;
295 {
296     static char fullname[ MAXKTCNAMELEN + MAXKTCNAMELEN +
297         MAXKTCREALMLEN + 3 ];
298
299     /* always must have name */
300     if ( !name || !name[0] ) { return NULL; }
301     strcpy(fullname, name);
302
303     /* might have instance */
304     if ( inst && inst[0] ) {
305         if ( !sep || !sep[0] ) { return NULL; }
306
307         strcat(fullname, sep);
308         strcat(fullname, inst);
309     }
310
311     /* might have realm */
312     if ( realm && realm[0] )
313     {
314         strcat(fullname, "@");
315         strcat(fullname, realm);
316     }
317
318     if ( FindUser(adir, fullname) ) {
319         return fullname;
320     } else {
321         return NULL;
322     }
323 }
324
325
326 /* make sure user authenticated on rx call acall is in list of valid
327     users. Copy the "real name" of the authenticated user into namep
328     if a pointer is passed.
329 */
330 afs_int32 afsconf_SuperUser(adir, acall, namep)
331 struct afsconf_dir *adir;
332 struct rx_call *acall;
333 char *namep; {
334     register struct rx_connection *tconn;
335     register afs_int32 code;
336     int flag;
337
338     LOCK_GLOBAL_MUTEX
339     if (!adir) {
340         UNLOCK_GLOBAL_MUTEX
341         return 0;
342     }
343
344     if (afsconf_GetNoAuthFlag(adir)) {
345         if (namep) strcpy(namep, "<NoAuth>");
346         UNLOCK_GLOBAL_MUTEX
347         return 1;
348     }
349
350     tconn = rx_ConnectionOf(acall);
351     code = rx_SecurityClassOf(tconn);
352     if (code == 0) {
353         UNLOCK_GLOBAL_MUTEX
354         return 0;           /* not authenticated at all, answer is no */
355     }
356     else if (code == 1) {
357         /* bcrypt tokens */
358         UNLOCK_GLOBAL_MUTEX
359         return 0;                       /* not supported any longer */
360     }
361     else if (code == 2) {
362         char tname[MAXKTCNAMELEN];      /* authentication from ticket */
363         char tinst[MAXKTCNAMELEN];
364         char tcell[MAXKTCREALMLEN];
365         char tcell_l[MAXKTCREALMLEN];
366         char *tmp;
367         
368         /* keep track of which one actually authorized request */
369         char uname[MAXKTCNAMELEN+MAXKTCNAMELEN+MAXKTCREALMLEN+3];
370
371         afs_uint32 exp;
372         static char lcell[MAXCELLCHARS] = "";
373         static char lrealm[AFS_REALM_SZ] = "";
374         
375         /* get auth details from server connection */
376         code = rxkad_GetServerInfo
377             (acall->conn, (afs_int32 *) 0, &exp, 
378                 tname, tinst, tcell, (afs_int32 *) 0);
379         if (code) {
380             UNLOCK_GLOBAL_MUTEX
381             return 0; /* bogus connection/other error */
382         }
383
384         /* don't bother checking anything else if tix have expired */
385 #ifdef AFS_PTHREAD_ENV
386         if (exp < clock_Sec()) {
387 #else
388         if (exp < FT_ApproxTime()) {
389 #endif
390             UNLOCK_GLOBAL_MUTEX
391             return 0;   /* expired tix */
392         }
393
394         /* generate lowercased version of cell name */
395         strcpy(tcell_l, tcell);
396         tmp = tcell_l;
397         while ( *tmp ) { *tmp = tolower(*tmp); *tmp++; }
398
399         /* determine local cell name. It's static, so will only get
400            calculated the first time through */
401         if (!lcell[0])
402             afsconf_GetLocalCell(adir, lcell, sizeof(lcell));
403
404         /* if running a krb environment, also get the local realm */
405         /* note - this assumes AFS_REALM_SZ <= MAXCELLCHARS */
406         /* just set it to lcell if it fails */
407         if (!lrealm[0]) {
408             if (afs_krb_get_lrealm(lrealm, 0) != 0) /* KSUCCESS */
409                 strncpy(lrealm, lcell, AFS_REALM_SZ);
410         }
411
412
413         /* start with no uname and no authorization */
414         strcpy(uname, "");
415         flag = 0;
416
417         /* localauth special case */
418         if ( strlen(tinst) == 0 && strlen(tcell) == 0 && 
419                 !strcmp(tname, AUTH_SUPERUSER) ) {
420             strcpy(uname, "<LocalAuth>");
421             flag = 1;
422
423         /* cell of connection matches local cell or krb4 realm */
424         } else if ( !strcasecmp(tcell, lcell) || !strcasecmp(tcell,lrealm) ) {
425             if ( (tmp = CompFindUser(adir, tname, ".", tinst, NULL)) ) {
426                 strcpy(uname, tmp);
427                 flag = 1;
428 #ifdef notyet
429             } else if ( (tmp = CompFindUser(adir, tname, "/", tinst, NULL)) ) {
430                 strcpy(uname, tmp);
431                 flag = 1;
432 #endif
433             }
434
435         /* cell of conn doesn't match local cell or realm */
436         } else {
437             if ( (tmp = CompFindUser(adir, tname, ".", tinst, tcell)) ) {
438                 strcpy(uname, tmp);
439                 flag = 1;
440 #ifdef notyet
441             } else if ( (tmp = CompFindUser(adir, tname, "/", tinst, tcell)) ) {
442                 strcpy(uname, tmp);
443                 flag = 1;
444 #endif
445             } else if ( (tmp = CompFindUser(adir, tname, ".", tinst, tcell_l)) ) {
446                 strcpy(uname, tmp);
447                 flag = 1;
448 #ifdef notyet
449             } else if ( (tmp = CompFindUser(adir, tname, "/", tinst, tcell_l)) ) {
450                 strcpy(uname, tmp);
451                 flag = 1;
452 #endif
453             }
454         }
455
456         if (namep)
457             strcpy(namep, uname);
458         UNLOCK_GLOBAL_MUTEX
459         return flag;
460     }
461     else { /* some other auth type */
462         UNLOCK_GLOBAL_MUTEX
463         return  0;          /* mysterious, just say no */
464     }
465 }