2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
19 #include <afs/pthread_glock.h>
22 #include <rx/rx_identity.h>
23 #include <afs/afsutil.h>
24 #include <afs/fileutil.h>
28 #include "cellconfig.h"
30 #include "afs/audit.h"
32 /* The display names for localauth and noauth identities; they aren't used
33 * inside tickets or anything, but just serve as something to display in logs,
35 #define AFS_LOCALAUTH_NAME "<LocalAuth>"
36 #define AFS_LOCALAUTH_LEN (sizeof(AFS_LOCALAUTH_NAME)-1)
37 #define AFS_NOAUTH_NAME "<NoAuth>"
38 #define AFS_NOAUTH_LEN (sizeof(AFS_NOAUTH_NAME)-1)
40 static int ParseLine(char *buffer, struct rx_identity *user);
43 UserListFileName(struct afsconf_dir *adir,
44 char *buffer, size_t len)
46 strcompose(buffer, len, adir->name, "/", AFSDIR_ULIST_FILE, (char *)NULL);
51 afsconf_CheckAuth(void *arock, struct rx_call *acall)
53 struct afsconf_dir *adir = (struct afsconf_dir *) arock;
56 rc = ((afsconf_SuperUser(adir, acall, NULL) == 0) ? 10029 : 0);
60 #endif /* !defined(UKERNEL) */
63 GetNoAuthFlag(struct afsconf_dir *adir)
65 if (access(AFSDIR_SERVER_NOAUTH_FILEPATH, 0) == 0) {
66 osi_audit(NoAuthEvent, 0, AUD_END); /* some random server is running noauth */
67 return 1; /* if /usr/afs/local/NoAuth file exists, allow access */
74 afsconf_GetNoAuthFlag(struct afsconf_dir *adir)
79 rc = GetNoAuthFlag(adir);
85 afsconf_SetNoAuthFlag(struct afsconf_dir *adir, int aflag)
91 /* turn off noauth flag */
92 code = (unlink(AFSDIR_SERVER_NOAUTH_FILEPATH) ? errno : 0);
93 osi_audit(NoAuthDisableEvent, code, AUD_END);
95 /* try to create file */
97 open(AFSDIR_SERVER_NOAUTH_FILEPATH, O_CREAT | O_TRUNC | O_RDWR,
101 osi_audit(NoAuthEnableEvent, 0, AUD_END);
103 osi_audit(NoAuthEnableEvent, errno, AUD_END);
109 * Remove an identity from the UserList file
111 * This function removes the given identity from the user list file.
112 * For the purposes of identifying entries to remove, only the
113 * type and exportedName portions of the identity are used. Callers
114 * should remember that a given identity may be listed in the file in
115 * a number of different ways.
118 * A structure representing the configuration directory currently
121 * The RX identity to delete
124 * 0 on success, an error code on failure
128 afsconf_DeleteIdentity(struct afsconf_dir *adir, struct rx_identity *user)
139 struct rx_identity identity;
142 memset(&identity, 0, sizeof(struct rx_identity));
145 UserListFileName(adir, tbuffer, sizeof tbuffer);
149 * We attempt to fully resolve this pathname, so that the rename
150 * of the temporary file will work even if UserList is a symlink
151 * into a different filesystem.
153 char resolved_path[1024];
155 if (realpath(tbuffer, resolved_path)) {
156 strcpy(tbuffer, resolved_path);
159 #endif /* AFS_NT40_ENV */
160 tf = fopen(tbuffer, "r");
165 code = stat(tbuffer, &tstat);
170 strcpy(nbuffer, tbuffer);
171 strcat(nbuffer, ".NXX");
172 nf = fopen(nbuffer, "w+");
181 /* check for our user id */
182 tp = fgets(nbuffer, sizeof(nbuffer), tf);
186 copy = strdup(nbuffer);
191 code = ParseLine(copy, &identity);
192 if (code == 0 && rx_identity_match(user, &identity)) {
193 /* found the guy, don't copy to output file */
196 /* otherwise copy original line to output */
197 fprintf(nf, "%s", nbuffer);
200 rx_identity_freeContents(&identity);
205 if (fclose(nf) == EOF)
207 strcpy(nbuffer, tbuffer);
208 strcat(nbuffer, ".NXX"); /* generate new file name again */
211 flag = rk_rename(nbuffer, tbuffer);
213 flag = chmod(tbuffer, tstat.st_mode);
217 /* finally, decide what to return to the caller */
220 return EIO; /* something mysterious went wrong */
222 return ENOENT; /* entry wasn't found, no changes made */
223 return 0; /* everything was fine */
227 * Remove a legacy Kerberos 4 name from the UserList file.
229 * This function removes a Kerberos 4 name from the super user list. It
230 * can only remove names which were added by the afsconf_AddUser interface,
231 * or with an explicit Kerberos v4 type.
234 * A structure representing the configuration directory
236 * The Kerberos v4 name to remove
239 * 0 on success, an error code upon failure.
241 * Note that this function is deprecated. New callers should use
242 * afsconf_DeleteIdentity instead.
246 afsconf_DeleteUser(struct afsconf_dir *adir, char *name)
248 struct rx_identity *user;
251 user = rx_identity_new(RX_ID_KRB4, name, name, strlen(name));
255 code = afsconf_DeleteIdentity(adir, user);
257 rx_identity_free(&user);
262 /* This is a multi-purpose funciton for use by either
263 * GetNthIdentity or GetNthUser. The parameter 'id' indicates
264 * whether we are counting all identities (if true), or just
265 * ones which can be represented by the old-style interfaces
268 GetNthIdentityOrUser(struct afsconf_dir *dir, int count,
269 struct rx_identity **identity, int id)
273 struct rx_identity fileUser;
277 UserListFileName(dir, tbuffer, sizeof(tbuffer));
278 bp = BufioOpen(tbuffer, O_RDONLY, 0);
284 code = BufioGets(bp, tbuffer, sizeof(tbuffer));
288 code = ParseLine(tbuffer, &fileUser);
292 if (id || fileUser.kind == RX_ID_KRB4)
298 rx_identity_freeContents(&fileUser);
301 *identity = rx_identity_copy(&fileUser);
302 rx_identity_freeContents(&fileUser);
312 * Return the Nth super user identity from the UserList
315 * A structure representing the configuration directory
317 * A count (from zero) of the entries to return from the
319 * @param[out] identity
320 * A pointer to the Nth identity
322 * 0 on success, non-zero on failure
326 afsconf_GetNthIdentity(struct afsconf_dir *dir, int count,
327 struct rx_identity **identity)
329 return GetNthIdentityOrUser(dir, count, identity, 1);
333 * Return the Nth Kerberos v4 identity from the UserList
335 * This returns the Nth old, kerberos v4 style name from
336 * the UserList file. In counting entries it skips any other
337 * name types it encounters - so will hide any new-style
338 * identities from its callers.
341 * A structure representing the configuration directory
343 * A count (from zero) of the entries to return from the
346 * A string in which to write the name of the Nth identity
348 * The length of the buffer passed in abuffer
350 * 0 on success, non-zero on failure
352 * This function is deprecated, all new callers should use
353 * GetNthIdentity instead. This function is particularly dangerous
354 * as it will hide any new-style identities from callers.
358 afsconf_GetNthUser(struct afsconf_dir *adir, afs_int32 an, char *abuffer,
359 afs_int32 abufferLen)
361 struct rx_identity *identity;
364 code = GetNthIdentityOrUser(adir, an, &identity, 0);
366 strlcpy(abuffer, identity->displayName, abufferLen);
367 rx_identity_free(&identity);
373 * Parse a UserList list
375 * Parse a line of data from a UserList file
377 * This parses a line of data in a UserList, and populates the passed
378 * rx_identity structure with the information about the user.
380 * @param buffer A string containing the line to be parsed
381 * @param user The user structure to be populated
383 * Note that the user->displayName, and user->exportedName.val fields
384 * must be freed with free() by the caller.
386 * This function damages the buffer thats passed to it. Callers are
387 * expected to make a copy if they want the buffer preserved.
390 * 0 on success, non-zero on failure.
394 ParseLine(char *buffer, struct rx_identity *user)
405 if (buffer[0] == ' ') { /* extended names have leading space */
407 code = sscanf(ptr, "%i", &kind);
411 strsep(&ptr, " "); /* skip the bit we just read with scanf */
412 ename = strsep(&ptr, " "); /* Pull out the ename */
413 displayName = strsep(&ptr, " "); /* Display name runs to the end */
414 if (ename == NULL || displayName == NULL)
417 decodedName = malloc(strlen(ename));
418 if (decodedName == NULL)
421 len = base64_decode(ename, decodedName);
427 rx_identity_populate(user, kind, displayName, decodedName, len);
430 return 0; /* Success ! */
433 /* No extended name, try for a legacy name */
434 code = sscanf(buffer, "%64s", name);
438 rx_identity_populate(user, RX_ID_KRB4, name, name, strlen(name));
443 * Check if a given identity is in the UserList file,
444 * and thus is a super user
447 * A structure representing the configuration directory to check
449 * The identity to check
451 * True if the user is listed in the UserList, otherwise false
455 afsconf_IsSuperIdentity(struct afsconf_dir *adir,
456 struct rx_identity *user)
460 struct rx_identity fileUser;
464 UserListFileName(adir, tbuffer, sizeof tbuffer);
465 bp = BufioOpen(tbuffer, O_RDONLY, 0);
470 code = BufioGets(bp, tbuffer, sizeof(tbuffer));
474 code = ParseLine(tbuffer, &fileUser);
478 match = rx_identity_match(user, &fileUser);
480 rx_identity_freeContents(&fileUser);
486 /* add a user to the user list, checking for duplicates */
488 afsconf_AddIdentity(struct afsconf_dir *adir, struct rx_identity *user)
496 if (afsconf_IsSuperIdentity(adir, user)) {
498 return EEXIST; /* already in the list */
501 UserListFileName(adir, tbuffer, sizeof tbuffer);
502 tf = fopen(tbuffer, "a+");
507 if (user->kind == RX_ID_KRB4) {
508 fprintf(tf, "%s\n", user->displayName);
510 base64_encode(user->exportedName.val, user->exportedName.len,
512 fprintf(tf, " %d %s %s\n", user->kind, ename, user->displayName);
525 afsconf_AddUser(struct afsconf_dir *adir, char *aname)
527 struct rx_identity *user;
530 user = rx_identity_new(RX_ID_KRB4, aname, aname, strlen(aname));
534 code = afsconf_AddIdentity(adir, user);
536 rx_identity_free(&user);
541 /* special CompFindUser routine that builds up a princ and then
542 calls finduser on it. If found, returns char * to user string,
543 otherwise returns NULL. The resulting string should be immediately
544 copied to other storage prior to release of mutex. */
546 CompFindUser(struct afsconf_dir *adir, char *name, char *sep, char *inst,
547 char *realm, struct rx_identity **identity)
549 static char fullname[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
550 struct rx_identity *testId;
552 /* always must have name */
553 if (!name || !name[0]) {
557 if (strlcpy(fullname, name, sizeof(fullname)) >= sizeof(fullname))
560 /* might have instance */
561 if (inst && inst[0]) {
562 if (!sep || !sep[0]) {
566 if (strlcat(fullname, sep, sizeof(fullname)) >= sizeof(fullname))
569 if (strlcat(fullname, inst, sizeof(fullname)) >= sizeof(fullname))
573 /* might have realm */
574 if (realm && realm[0]) {
575 if (strlcat(fullname, "@", sizeof(fullname)) >= sizeof(fullname))
578 if (strlcat(fullname, realm, sizeof(fullname)) >= sizeof(fullname))
582 testId = rx_identity_new(RX_ID_KRB4, fullname, fullname, strlen(fullname));
583 if (afsconf_IsSuperIdentity(adir, testId)) {
587 rx_identity_free(&testId);
591 rx_identity_free(&testId);
596 kerberosSuperUser(struct afsconf_dir *adir, char *tname, char *tinst,
597 char *tcell, struct rx_identity **identity)
599 char tcell_l[MAXKTCREALMLEN] = "";
604 /* generate lowercased version of cell name */
606 opr_lcstring(tcell_l, tcell, sizeof(tcell_l));
608 code = afsconf_IsLocalRealmMatch(adir, &islocal, tname, tinst, tcell);
613 /* start with no authorization */
616 /* localauth special case */
617 if ((tinst == NULL || strlen(tinst) == 0) &&
618 (tcell == NULL || strlen(tcell) == 0)
619 && !strcmp(tname, AUTH_SUPERUSER)) {
621 *identity = rx_identity_new(RX_ID_KRB4, AFS_LOCALAUTH_NAME,
622 AFS_LOCALAUTH_NAME, AFS_LOCALAUTH_LEN);
625 /* cell of connection matches local cell or one of the realms */
626 } else if (islocal) {
627 if (CompFindUser(adir, tname, ".", tinst, NULL, identity)) {
630 /* cell of conn doesn't match local cell or realm */
632 if (CompFindUser(adir, tname, ".", tinst, tcell, identity)) {
634 } else if (CompFindUser(adir, tname, ".", tinst, tcell_l, identity)) {
643 rxkadSuperUser(struct afsconf_dir *adir, struct rx_call *acall,
644 struct rx_identity **identity)
646 char tname[MAXKTCNAMELEN]; /* authentication from ticket */
647 char tinst[MAXKTCNAMELEN];
648 char tcell[MAXKTCREALMLEN];
653 /* get auth details from server connection */
654 code = rxkad_GetServerInfo(rx_ConnectionOf(acall), NULL, &exp, tname,
657 return 0; /* bogus connection/other error */
659 return kerberosSuperUser(adir, tname, tinst, tcell, identity);
663 * Check whether the user authenticated on a given RX call is a super
664 * user or not. If they are, return a pointer to the identity of that
668 * The configuration directory currently in use
670 * The RX call whose authenticated identity is being checked
671 * @param[out] identity
672 * The RX identity of the user. Caller must free this structure.
674 * True if the user is a super user, or if the server is running
675 * in noauth mode. Otherwise, false.
678 afsconf_SuperIdentity(struct afsconf_dir *adir, struct rx_call *acall,
679 struct rx_identity **identity)
681 struct rx_connection *tconn;
691 if (afsconf_GetNoAuthFlag(adir)) {
693 *identity = rx_identity_new(RX_ID_KRB4, AFS_NOAUTH_NAME,
694 AFS_NOAUTH_NAME, AFS_NOAUTH_LEN);
699 tconn = rx_ConnectionOf(acall);
700 code = rx_SecurityClassOf(tconn);
703 return 0; /* not authenticated at all, answer is no */
704 } else if (code == 1) {
707 return 0; /* not supported any longer */
708 } else if (code == 2) {
709 flag = rxkadSuperUser(adir, acall, identity);
712 } else { /* some other auth type */
714 return 0; /* mysterious, just say no */
719 * Check whether the user authenticated on a given RX call is a super
720 * user or not. If they are, return a pointer to the name of that
724 * The configuration directory currently in use
726 * The RX call whose authenticated identity is being checked
728 * A printable version of the name of the user
730 * True if the user is a super user, or if the server is running
731 * in noauth mode. Otherwise, false.
733 * This function is provided for backwards compatibility. New callers
734 * should use the afsconf_SuperIdentity function.
738 afsconf_SuperUser(struct afsconf_dir *adir, struct rx_call *acall,
741 struct rx_identity *identity;
745 ret = afsconf_SuperIdentity(adir, acall, &identity);
747 if (identity->kind == RX_ID_KRB4) {
748 strlcpy(namep, identity->displayName, MAXKTCNAMELEN-1);
750 snprintf(namep, MAXKTCNAMELEN-1, "eName: %s",
751 identity->displayName);
753 rx_identity_free(&identity);
756 ret = afsconf_SuperIdentity(adir, acall, NULL);