"Fossies" - the Fresh Open Source Software Archive

Member "sudo-1.9.11p3/plugins/sudoers/auth/aix_auth.c" (12 Jun 2022, 8317 Bytes) of package /linux/misc/sudo-1.9.11p3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "aix_auth.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * SPDX-License-Identifier: ISC
    3  *
    4  * Copyright (c) 1999-2005, 2007-2018 Todd C. Miller <Todd.Miller@sudo.ws>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  *
   18  * Sponsored in part by the Defense Advanced Research Projects
   19  * Agency (DARPA) and Air Force Research Laboratory, Air Force
   20  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
   21  */
   22 
   23 /*
   24  * This is an open source non-commercial project. Dear PVS-Studio, please check it.
   25  * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
   26  */
   27 
   28 #include <config.h>
   29 
   30 #ifdef HAVE_AIXAUTH
   31 
   32 #include <sys/types.h>
   33 #include <sys/wait.h>
   34 #include <stdio.h>
   35 #include <stdlib.h>
   36 #include <string.h>
   37 #include <unistd.h>
   38 #include <ctype.h>
   39 #include <errno.h>
   40 #include <pwd.h>
   41 #include <signal.h>
   42 #include <usersec.h>
   43 
   44 #include "sudoers.h"
   45 #include "sudo_auth.h"
   46 
   47 /*
   48  * For a description of the AIX authentication API, see
   49  * http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf1/authenticate.htm
   50  */
   51 
   52 #ifdef HAVE_PAM
   53 # define AIX_AUTH_UNKNOWN   0
   54 # define AIX_AUTH_STD       1
   55 # define AIX_AUTH_PAM       2
   56 
   57 static int
   58 sudo_aix_authtype(void)
   59 {
   60     size_t linesize = 0;
   61     ssize_t len;
   62     char *cp, *line = NULL;
   63     bool in_stanza = false;
   64     int authtype = AIX_AUTH_UNKNOWN;
   65     FILE *fp;
   66     debug_decl(sudo_aix_authtype, SUDOERS_DEBUG_AUTH);
   67 
   68     if ((fp = fopen("/etc/security/login.cfg", "r")) == NULL)
   69     debug_return_int(AIX_AUTH_UNKNOWN);
   70 
   71     while ((len = getdelim(&line, &linesize, '\n', fp)) != -1) {
   72     /* First remove comments. */
   73     if ((cp = strchr(line, '#')) != NULL) {
   74         *cp = '\0';
   75         len = (ssize_t)(cp - line);
   76     }
   77 
   78     /* Next remove trailing newlines and whitespace. */
   79     while (len > 0 && isspace((unsigned char)line[len - 1]))
   80         line[--len] = '\0';
   81 
   82     /* Skip blank lines. */
   83     if (len == 0)
   84         continue;
   85 
   86     /* Match start of the usw stanza. */
   87     if (!in_stanza) {
   88         if (strncmp(line, "usw:", 4) == 0)
   89         in_stanza = true;
   90         continue;
   91     }
   92 
   93     /* Check for end of the usw stanza. */
   94     if (!isblank((unsigned char)line[0])) {
   95         in_stanza = false;
   96         break;
   97     }
   98 
   99     /* Skip leading blanks. */
  100     cp = line;
  101     do {
  102         cp++;
  103     } while (isblank((unsigned char)*cp));
  104 
  105     /* Match "auth_type = (PAM_AUTH|STD_AUTH)". */
  106     if (strncmp(cp, "auth_type", 9) != 0)
  107         continue;
  108     cp += 9;
  109     while (isblank((unsigned char)*cp))
  110         cp++;
  111     if (*cp++ != '=')
  112         continue;
  113     while (isblank((unsigned char)*cp))
  114         cp++;
  115     if (strcmp(cp, "PAM_AUTH") == 0) {
  116         authtype = AIX_AUTH_PAM;
  117         break;
  118     }
  119     if (strcmp(cp, "STD_AUTH") == 0) {
  120         authtype = AIX_AUTH_STD;
  121         break;
  122     }
  123     }
  124     free(line);
  125     fclose(fp);
  126 
  127     debug_return_int(authtype);
  128 }
  129 #endif /* HAVE_PAM */
  130 
  131 int
  132 sudo_aix_init(struct passwd *pw, sudo_auth *auth)
  133 {
  134     debug_decl(sudo_aix_init, SUDOERS_DEBUG_AUTH);
  135 
  136 #ifdef HAVE_PAM
  137     /* Check auth_type in /etc/security/login.cfg. */
  138     if (sudo_aix_authtype() == AIX_AUTH_PAM) {
  139     if (sudo_pam_init_quiet(pw, auth) == AUTH_SUCCESS) {
  140         /* Fail AIX authentication so we can use PAM instead. */
  141         debug_return_int(AUTH_FAILURE);
  142     }
  143     }
  144 #endif
  145     debug_return_int(AUTH_SUCCESS);
  146 }
  147 
  148 /* Ignore AIX password incorrect message */
  149 static bool
  150 sudo_aix_valid_message(const char *message)
  151 {
  152     const char *cp;
  153     const char badpass_msgid[] = "3004-300";
  154     debug_decl(sudo_aix_valid_message, SUDOERS_DEBUG_AUTH);
  155 
  156     if (message == NULL || message[0] == '\0')
  157     debug_return_bool(false);
  158 
  159     /* Match "3004-300: You entered an invalid login name or password" */
  160     for (cp = message; *cp != '\0'; cp++) {
  161     if (isdigit((unsigned char)*cp)) {
  162         if (strncmp(cp, badpass_msgid, strlen(badpass_msgid)) == 0)
  163         debug_return_bool(false);
  164         break;
  165     }
  166     }
  167     debug_return_bool(true);
  168 }
  169 
  170 /* 
  171  * Change the user's password.  If root changes the user's password
  172  * the ADMCHG flag is set on the account (and the user must change
  173  * it again) so we run passwd(1) as the user.  This does mean that
  174  * the user will need to re-enter their original password again,
  175  * unlike with su(1).  We may consider using pwdadm(1) as root to
  176  * change the password and then clear the flag in the future.
  177  */
  178 static bool
  179 sudo_aix_change_password(const char *user)
  180 {
  181     struct sigaction sa, savechld;
  182     pid_t child, pid;
  183     bool ret = false;
  184     sigset_t mask;
  185     int status;
  186     debug_decl(sudo_aix_change_password, SUDOERS_DEBUG_AUTH);
  187 
  188     /* Set SIGCHLD handler to default since we call waitpid() below. */
  189     memset(&sa, 0, sizeof(sa));                
  190     sigemptyset(&sa.sa_mask);
  191     sa.sa_flags = SA_RESTART;     
  192     sa.sa_handler = SIG_DFL;
  193     (void) sigaction(SIGCHLD, &sa, &savechld);
  194 
  195     switch (child = sudo_debug_fork()) {
  196     case -1:
  197     /* error */
  198     sudo_warn("%s", U_("unable to fork"));
  199     break;
  200     case 0:
  201     /* child, run passwd(1) */
  202     sigemptyset(&mask);
  203     sigaddset(&mask, SIGINT);
  204     sigaddset(&mask, SIGQUIT);
  205     (void) sigprocmask(SIG_UNBLOCK, &mask, NULL);
  206     set_perms(PERM_USER);
  207     execl("/usr/bin/passwd", "passwd", user, (char *)NULL);
  208     sudo_warn("passwd");
  209     _exit(127);
  210     /* NOTREACHED */
  211     default:
  212     /* parent */
  213     break;
  214     }
  215 
  216     /* Wait for passwd(1) to complete. */
  217     do {
  218     pid = waitpid(child, &status, 0);
  219     } while (pid == -1 && errno == EINTR);
  220     sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
  221     "child (%d) exit value %d", (int)child, status);
  222     if (pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0)
  223     ret = true;
  224 
  225     /* Restore saved SIGCHLD handler. */
  226     (void) sigaction(SIGCHLD, &savechld, NULL);
  227 
  228     debug_return_bool(ret);
  229 }
  230 
  231 int
  232 sudo_aix_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback)
  233 {
  234     char *pass, *message = NULL;
  235     int result = 1, reenter = 0;
  236     int ret = AUTH_SUCCESS;
  237     debug_decl(sudo_aix_verify, SUDOERS_DEBUG_AUTH);
  238 
  239     if (IS_NONINTERACTIVE(auth))
  240         debug_return_int(AUTH_NONINTERACTIVE);
  241 
  242     do {
  243     pass = auth_getpass(prompt, SUDO_CONV_PROMPT_ECHO_OFF, callback);
  244     if (pass == NULL)
  245         break;
  246     free(message);
  247     message = NULL;
  248     result = authenticate(pw->pw_name, pass, &reenter, &message);
  249     freezero(pass, strlen(pass));
  250     prompt = message;
  251     } while (reenter);
  252 
  253     if (result != 0) {
  254     /* Display error message, if any. */
  255     if (sudo_aix_valid_message(message))
  256         sudo_printf(SUDO_CONV_ERROR_MSG|SUDO_CONV_PREFER_TTY,
  257         "%s", message);
  258     ret = pass ? AUTH_FAILURE : AUTH_INTR;
  259     }
  260     free(message);
  261     message = NULL;
  262 
  263     /* Check if password expired and allow user to change it if possible. */
  264     if (ret == AUTH_SUCCESS) {
  265     result = passwdexpired(pw->pw_name, &message);
  266     if (message != NULL && message[0] != '\0') {
  267         int msg_type = SUDO_CONV_PREFER_TTY;
  268         msg_type |= result ? SUDO_CONV_ERROR_MSG : SUDO_CONV_INFO_MSG,
  269         sudo_printf(msg_type, "%s", message);
  270         free(message);
  271         message = NULL;
  272     }
  273     switch (result) {
  274     case 0:
  275         /* password not expired. */
  276         break;
  277     case 1:
  278         /* password expired, user must change it */
  279         if (!sudo_aix_change_password(pw->pw_name)) {
  280         sudo_warnx(U_("unable to change password for %s"), pw->pw_name);
  281         ret = AUTH_FATAL;
  282         }
  283         break;
  284     case 2:
  285         /* password expired, only admin can change it */
  286         ret = AUTH_FATAL;
  287         break;
  288     default:
  289         /* error (-1) */
  290         sudo_warn("passwdexpired");
  291         ret = AUTH_FATAL;
  292         break;
  293     }
  294     }
  295 
  296     debug_return_int(ret);
  297 }
  298 
  299 int
  300 sudo_aix_cleanup(struct passwd *pw, sudo_auth *auth, bool force)
  301 {
  302     debug_decl(sudo_aix_cleanup, SUDOERS_DEBUG_AUTH);
  303 
  304     /* Unset AUTHSTATE as it may not be correct for the runas user. */
  305     if (sudo_unsetenv("AUTHSTATE") == -1)
  306     debug_return_int(AUTH_FAILURE);
  307 
  308     debug_return_int(AUTH_SUCCESS);
  309 }
  310 
  311 #endif /* HAVE_AIXAUTH */