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