Example #1
0
File: pam_tally.c Project: aosm/pam
static int get_tally( tally_t *tally, 
                              uid_t uid, 
                              const char *filename, 
                              FILE **TALLY,
		              struct fail_s *fsp) 
  {
    struct stat fileinfo;
    int lstat_ret = lstat(filename,&fileinfo);

    if ( lstat_ret && *tally!=TALLY_HI ) {
      int oldmask = umask(077);
      *TALLY=fopen(filename, "a");
      /* Create file, or append-open in pathological case. */
      umask(oldmask);
      if ( !*TALLY ) {
        _pam_log(LOG_ALERT, "Couldn't create %s",filename);
        return PAM_AUTH_ERR;
      }
      lstat_ret = fstat(fileno(*TALLY),&fileinfo);
      fclose(*TALLY);
    }

    if ( lstat_ret ) {
      _pam_log(LOG_ALERT, "Couldn't stat %s",filename);
      return PAM_AUTH_ERR;
    }

    if((fileinfo.st_mode & S_IWOTH) || !S_ISREG(fileinfo.st_mode)) {
      /* If the file is world writable or is not a
         normal file, return error */
      _pam_log(LOG_ALERT,
               "%s is either world writable or not a normal file",
               filename);
      return PAM_AUTH_ERR;
    }

    if ( ! ( *TALLY = fopen(filename,(*tally!=TALLY_HI)?"r+":"r") ) ) {
      _pam_log(LOG_ALERT, "Error opening %s for update", filename);

/* Discovering why account service fails: e/uid are target user.
 *
 *      perror(MODULE_NAME);
 *      fprintf(stderr,"uid %d euid %d\n",getuid(), geteuid());
 */
      return PAM_AUTH_ERR;
    }

    if ( fseek( *TALLY, uid * sizeof(struct faillog), SEEK_SET ) ) {
          _pam_log(LOG_ALERT, "fseek failed %s", filename);
                return PAM_AUTH_ERR;
    }
                    
    if ( fileinfo.st_size <= uid * sizeof(struct faillog) ) {

	memset(fsp, 0, sizeof(struct faillog));
	*tally=0;
	fsp->fs_faillog.fail_time = time(NULL);

    } else if (( fread((char *) &fsp->fs_faillog,
		       sizeof(struct faillog), 1, *TALLY) )==0 ) {

	*tally=0; /* Assuming a gappy filesystem */

    } else {

	*tally = fsp->fs_faillog.fail_cnt;

    }
              
    return PAM_SUCCESS;
  }
Example #2
0
File: pam_tally.c Project: aosm/pam
static int tally_bump (int inc,
                           pam_handle_t *pamh,
                           int flags,
                           int argc,
                           const char **argv) {
  uid_t uid;

  int 
    fail_on_error = FALSE;
  tally_t
    tally         = 0;  /* !TALLY_HI --> Log opened for update */

  char
    no_magic_root          = FALSE;

  char 
    filename[ FILENAME_MAX ] = DEFAULT_LOGFILE;

  /* Should probably decode the parameters before anything else. */

  {
    for ( ; argc-- > 0; ++argv ) {

      /* generic options.. um, ignored. :] */
      
      if ( ! strcmp( *argv, "no_magic_root" ) ) {
        no_magic_root = TRUE;
      }
      else if ( ! strncmp( *argv, "file=", 5 ) ) {
        char const 
          *from = (*argv)+5;
        char
          *to   = filename;
        if ( *from!='/' || strlen(from)>FILENAME_MAX-1 ) {
          _pam_log(LOG_ERR,
                   MODULE_NAME ": filename not /rooted or too long; ",
                   *argv);
          RETURN_ERROR( PAM_AUTH_ERR );
        }
        while ( ( *to++ = *from++ ) );        
      }
      else if ( ! strcmp( *argv, "onerr=fail" ) ) {
        fail_on_error=TRUE;
      }
      else if ( ! strcmp( *argv, "onerr=succeed" ) ) {
        fail_on_error=FALSE;
      }
      else {
        _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv);
      }
    } /* for() */
  }

  {
    FILE
      *TALLY = NULL;
    const char
      *user  = NULL,
      *remote_host = NULL,
      *cur_tty = NULL;
    struct fail_s fs, *fsp = &fs;

    int i=pam_get_uid(pamh, &uid, &user);
    if ( i != PAM_SUCCESS ) RETURN_ERROR( i );

    i=get_tally( &tally, uid, filename, &TALLY, fsp );

    /* to remember old fail time (for locktime) */
    fsp->fs_fail_time = fsp->fs_faillog.fail_time;
    fsp->fs_faillog.fail_time = time(NULL);
    (void) pam_get_item(pamh, PAM_RHOST, (const void **)&remote_host);
    if (!remote_host) {

    	(void) pam_get_item(pamh, PAM_TTY, (const void **)&cur_tty);
	if (!cur_tty) {
    	    strncpy(fsp->fs_faillog.fail_line, "unknown",
		    sizeof(fsp->fs_faillog.fail_line) - 1);
	    fsp->fs_faillog.fail_line[sizeof(fsp->fs_faillog.fail_line)-1] = 0;
	} else {
    	    strncpy(fsp->fs_faillog.fail_line, cur_tty,
		    sizeof(fsp->fs_faillog.fail_line)-1);
	    fsp->fs_faillog.fail_line[sizeof(fsp->fs_faillog.fail_line)-1] = 0;
	}

    } else {
    	strncpy(fsp->fs_faillog.fail_line, remote_host,
		(size_t)sizeof(fsp->fs_faillog.fail_line));
	fsp->fs_faillog.fail_line[sizeof(fsp->fs_faillog.fail_line)-1] = 0;
    }
    if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); }
    
    if ( no_magic_root || getuid() ) {       /* no_magic_root kills uid test */

      tally+=inc;
      
      if ( tally==TALLY_HI ) { /* Overflow *and* underflow. :) */
        tally-=inc;
        _pam_log(LOG_ALERT,"Tally %sflowed for user %s",
                 (inc<0)?"under":"over",user);
      }
    }
    
    i=set_tally( tally, uid, filename, &TALLY, fsp );
    if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); }
  }

  return PAM_SUCCESS;
} 
Example #3
0
int _pam_parse (int argc, const char **argv) {
    int ctrl = 0;
    const char *current_secret = NULL;

    /* otherwise the list will grow with each call */
    memset(tac_srv, 0, sizeof(tacplus_server_t) * TAC_PLUS_MAXSERVERS);
    tac_srv_no = 0;

    tac_service[0] = 0;
    tac_protocol[0] = 0;
    tac_prompt[0] = 0;
    tac_login[0] = 0;

    for (ctrl = 0; argc-- > 0; ++argv) {
        if (!strcmp (*argv, "debug")) { /* all */
            ctrl |= PAM_TAC_DEBUG;
        } else if (!strcmp (*argv, "use_first_pass")) {
            ctrl |= PAM_TAC_USE_FIRST_PASS;
        } else if (!strcmp (*argv, "try_first_pass")) { 
            ctrl |= PAM_TAC_TRY_FIRST_PASS;
        } else if (!strncmp (*argv, "service=", 8)) { /* author & acct */
            xstrcpy (tac_service, *argv + 8, sizeof(tac_service));
        } else if (!strncmp (*argv, "protocol=", 9)) { /* author & acct */
            xstrcpy (tac_protocol, *argv + 9, sizeof(tac_protocol));
        } else if (!strncmp (*argv, "prompt=", 7)) { /* authentication */
            xstrcpy (tac_prompt, *argv + 7, sizeof(tac_prompt));
            /* Replace _ with space */
            int chr;
            for (chr = 0; chr < strlen(tac_prompt); chr++) {
                if (tac_prompt[chr] == '_') {
                    tac_prompt[chr] = ' ';
                }
            }
        } else if (!strncmp (*argv, "login="******"acct_all")) {
            ctrl |= PAM_TAC_ACCT;
        } else if (!strncmp (*argv, "server=", 7)) { /* authen & acct */
            if(tac_srv_no < TAC_PLUS_MAXSERVERS) { 
                struct addrinfo hints, *servers, *server;
                int rv;
                char *port, server_buf[256];

                memset(&hints, 0, sizeof hints);
                hints.ai_family = AF_UNSPEC;  /* use IPv4 or IPv6, whichever */
                hints.ai_socktype = SOCK_STREAM;

                if (strlen(*argv + 7) >= sizeof(server_buf)) {
                    _pam_log(LOG_ERR, "server address too long, sorry");
                    continue;
                }
                strcpy(server_buf, *argv + 7);

                port = strchr(server_buf, ':');
                if (port != NULL) {
                    *port = '\0';
					port++;
                }
                if ((rv = getaddrinfo(server_buf, (port == NULL) ? "49" : port, &hints, &servers)) == 0) {
                    for(server = servers; server != NULL && tac_srv_no < TAC_PLUS_MAXSERVERS; server = server->ai_next) {
                        tac_srv[tac_srv_no].addr = server;
                        tac_srv[tac_srv_no].key = current_secret;
                        tac_srv_no++;
                    }
                } else {
                    _pam_log (LOG_ERR,
                        "skip invalid server: %s (getaddrinfo: %s)",
                        server_buf, gai_strerror(rv));
                }
            } else {
                _pam_log(LOG_ERR, "maximum number of servers (%d) exceeded, skipping",
                    TAC_PLUS_MAXSERVERS);
            }
        } else if (!strncmp (*argv, "secret=", 7)) {
            int i;

            current_secret = *argv + 7;     /* points right into argv (which is const) */

            /* if 'secret=' was given after a 'server=' parameter, fill in the current secret */
            for(i = tac_srv_no-1; i >= 0; i--) {
                if (tac_srv[i].key != NULL)
                    break;

                tac_srv[i].key = current_secret;
            }
        } else if (!strncmp (*argv, "timeout=", 8)) {
            /* FIXME atoi() doesn't handle invalid numeric strings well */
            tac_timeout = atoi(*argv + 8);

            if (tac_timeout < 0)
                tac_timeout = 0;
        } else {
            _pam_log (LOG_WARNING, "unrecognized option: %s", *argv);
        }
    }

    if (ctrl & PAM_TAC_DEBUG) {
        int n;

        _pam_log(LOG_DEBUG, "%d servers defined", tac_srv_no);

        for(n = 0; n < tac_srv_no; n++) {
            _pam_log(LOG_DEBUG, "server[%d] { addr=%s, key='%s' }", n, tac_ntop(tac_srv[n].addr->ai_addr), tac_srv[n].key);
        }

        _pam_log(LOG_DEBUG, "tac_service='%s'", tac_service);
        _pam_log(LOG_DEBUG, "tac_protocol='%s'", tac_protocol);
        _pam_log(LOG_DEBUG, "tac_prompt='%s'", tac_prompt);
        _pam_log(LOG_DEBUG, "tac_login='******'", tac_login);
    }

    return ctrl;
}    /* _pam_parse */
Example #4
0
PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh,
                                   int flags, int argc, const char **argv)
{

    const char *user = NULL, *passwd = NULL;
    struct passwd *pwd;
    int rval, status;
    pid_t pid;


    // For checking mount paths: (mount from + target)
    char path[PATH_MAX];
    char targetpath[PATH_MAX];
    char encfs_options[USERNAME_MAX];
    char fuse_options[USERNAME_MAX];
    char *targetpath_store;

    strcpy(default_encfs_options, "");
    strcpy(default_fuse_options, "");

    // For execing:
    char *arg[USERNAME_MAX];
    int arg_pos = 0;
    int i;
    int inpipe[2], outpipe[2];

    rval = pam_get_user(pamh, &user, NULL);
    if ((rval != PAM_SUCCESS) || (!user))
    {
        _pam_log(LOG_ERR, "can't get username: %s", pam_strerror(pamh, rval));
        return PAM_AUTH_ERR;
    }

    rval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) (void *) &passwd);
    if (rval != PAM_SUCCESS)
    {
        _pam_log(LOG_ERR, "Could not retrieve user's password");
        return PAM_AUTH_ERR;
    }

    if (!passwd)
    {
        rval = _set_auth_tok(pamh, flags, argc, argv);
        if (rval != PAM_SUCCESS)
        {
            return rval;
        }
        rval =
            pam_get_item(pamh, PAM_AUTHTOK, (const void **) (void *) &passwd);
        if (rval != PAM_SUCCESS || passwd == NULL)
        {
            _pam_log(LOG_ERR, "Could not retrieve user's password");
            return PAM_AUTH_ERR;
        }
    }
    if ((pwd = getpwnam(user)) == NULL)
    {
        _pam_log(LOG_ERR, "Could not getpwnam");
        return PAM_AUTH_ERR;
    }

    // Read configfile  
    if (!readconfig
        (pwd, pamh, pwd->pw_name, path, targetpath, encfs_options,
         fuse_options))
    {
        // DEBUG _pam_log(LOG_ERR,"No entry for user found in log");
        return PAM_IGNORE;
    }
    //DEBUG _pam_log(LOG_ERR,"Username : %s, Encpath : %s, Targetmount : %s",pwd->pw_name,path,targetpath);

    //Store targetpath
    targetpath_store = strdup(targetpath);
    if ((i =
         pam_set_data(pamh, "encfs_targetpath", targetpath_store,
                      targetpath_cleanup)) != PAM_SUCCESS)
    {
        _pam_log(LOG_ERR, "Storing targetpath FAIL");
        free(targetpath_store);
        return i;
    }

    // Check if we're mounted already.
    if (checkmnt(targetpath))
    {
        //DEBUG _pam_log(LOG_ERR,"Already mounted");
        return PAM_IGNORE;
    }



    /*  _pam_log(LOG_ERR,"Config output for %s:",user);
       _pam_log(LOG_ERR,"  path       : %s",path);
       _pam_log(LOG_ERR,"  targetpath : %s",targetpath);
       _pam_log(LOG_ERR,"  encfs      : %s %s",default_encfs_options,encfs_options);
       _pam_log(LOG_ERR,"  fuse       : %s %s",default_fuse_options,fuse_options); */


    arg_pos += buildCmd(arg, arg_pos, "encfs");
    arg_pos += buildCmd(arg, arg_pos, "-S");
    arg_pos += buildCmd(arg, arg_pos, default_encfs_options);
    arg_pos += buildCmd(arg, arg_pos, encfs_options);
    arg_pos += buildCmd(arg, arg_pos, path);
    arg_pos += buildCmd(arg, arg_pos, targetpath);

    if (strlen(default_fuse_options) > 0 && strlen(fuse_options) > 0)
        strcat(fuse_options, ",");

    strcat(fuse_options,default_fuse_options);
    if (strlen(fuse_options) > 0) {
        arg_pos += buildCmd(arg, arg_pos, "--");
        arg_pos += buildCmd(arg, arg_pos, "-o");
        arg_pos += buildCmd(arg, arg_pos, fuse_options);
    }
    arg[arg_pos] = NULL;

    /*  printf("Arguments : ");
       for (i = 0; i < arg_pos+1;i++) {
       _pam_log(LOG_ERR,"Data : %s",arg[i]);
       }

       _pam_log(LOG_ERR,"Number of arguments : %d",arg_pos); */


    /*  arg[0] = cmd;
       arg[1] = params;
       //  arg[2] = params2;
       arg[2] = params3;
       arg[3] = path;
       arg[4] = targetpath;
       arg[5] = fuseparams;
       arg[6] = fuseparams2;
       arg[7] = NULL; */



    if (pipe(inpipe) || pipe(outpipe))
    {
        _pam_log(LOG_ERR, "Failed to create pipe");
        return PAM_IGNORE;
    }

    // Execute 
    switch (pid = fork())
    {
        case -1:
            _pam_log(LOG_ERR, "Fork failed");
            return PAM_SERVICE_ERR;
        case 0:

            if (drop_permissions == 1)
                if ((initgroups(pwd->pw_name, pwd->pw_gid) == -1)
                    || (setgid(pwd->pw_gid) == -1)
                    || (setuid(pwd->pw_uid) == -1))
                {
                    _pam_log(LOG_ERR, "Dropping permissions failed");
                    return PAM_SERVICE_ERR;
                }
            close(outpipe[WRITE_END]);
            dup2(outpipe[READ_END], fileno(stdin));
            close(outpipe[READ_END]);

            close(inpipe[READ_END]);
            dup2(inpipe[WRITE_END], fileno(stdout));
            close(inpipe[WRITE_END]);

            // For some reason the current directory has to be set to targetpath (or path?) before exec'ing encfs through gdm
            chdir(targetpath);
            execvp("encfs", arg);
            char errstr[128];

            snprintf(errstr, 127, "%d - %s", errno, strerror(errno));
            _pam_log(LOG_ERR, "Exec failed - %s", errstr);
            exit(127);
    }

    int len;


    close(inpipe[WRITE_END]);
    close(outpipe[READ_END]);




    if (waitpid(pid, &status, WNOHANG) == 0)
    {
        len = write(outpipe[WRITE_END], passwd, (size_t) strlen(passwd));
        if ((len != (size_t) strlen(passwd))
            || (write(outpipe[WRITE_END], "\n", 1) != 1))
            _pam_log(LOG_ERR, "Did not send password to pipe (%d sent)", len);
        close(outpipe[WRITE_END]);
    }


    if (waitpid_timeout(pid, &status, 0))
    {
        _pam_log(LOG_ERR, "Timed out waiting for encfs, killing\n");
        kill(pid, SIGKILL);
    }

    int exitstatus = WEXITSTATUS(status);
    char buff[512];

    len = read(inpipe[READ_END], &buff, 511);
    close(inpipe[READ_END]);
    buff[len] = 0;
    if (!checkmnt(targetpath) && (len > 0 || exitstatus > 0))
    {
        _pam_log(LOG_ERR, "exitcode : %d, errorstring : %s", exitstatus,
                 buff);
        return PAM_AUTH_ERR;
    }
    else
    {
        return PAM_IGNORE;
    }
    return PAM_AUTH_ERR;
}
Example #5
0
PAM_EXTERN 
int pam_sm_chauthtok (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    int srv_i;
    int tac_fd;
    int status = PAM_TRY_AGAIN;
    int seq = 0;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    /* Preliminary call to check readiness of our module */
    if (flags & PAM_PRELIM_CHECK) {
    	/* Can we connect to TACACS? */
    	for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
    		if (ctrl & PAM_TAC_DEBUG)
    			_pam_log (LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );
    		tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
			if (tac_fd < 0) {
				_pam_log (LOG_ERR, "connection failed srv %d: %m", srv_i);
				if (srv_i == tac_srv_no-1) {
					_pam_log (LOG_ERR, "no more servers to connect");
					return PAM_TRY_AGAIN;
				}
				continue;
			}
    	}
    	close(tac_fd);
    	return PAM_SUCCESS;
    }

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);

    /* CHPASS does not send a password in data field,
     * user is prompted by a GETDATA reply packet
     */
    pass = malloc(5);
    strcpy(pass,"null");

    tty = _pam_get_terminal(pamh);
    if (!strncmp (tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    /* Attempt server connect */
    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        status = TAC_PLUS_AUTHEN_STATUS_FAIL;
        if (ctrl & PAM_TAC_DEBUG)
            _pam_log (LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
        if (tac_fd < 0) {
            _pam_log (LOG_ERR, "connection failed srv %d: %m", srv_i);
            if (srv_i == tac_srv_no-1) {
                _pam_log (LOG_ERR, "no more servers to connect");
                return PAM_AUTHINFO_UNAVAIL;
            }
            continue;
        }

        /* Send AUTHEN/START */
        if (tac_authen_send(tac_fd, user, pass, tty, r_addr, TAC_PLUS_AUTHEN_CHPASS, ctrl) < 0) {
            _pam_log (LOG_ERR, "error sending auth req to TACACS+ server");
            status = PAM_AUTHINFO_UNAVAIL;
        } else {
        	/* Read AUTHEN/REPLY and act on status */
			struct msg_status *msgstatus = malloc(sizeof(msg_status));

			do
			{
				tac_authen_read(msgstatus, tac_fd, ctrl, &seq);
				status = msgstatus->status;

				switch (status) {
					case TAC_PLUS_AUTHEN_STATUS_GETPASS:
						/* AUTHEN/CONT with password */
						if (ctrl & PAM_TAC_DEBUG)
							_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

						if (tac_cont_send(tac_fd, pass, ctrl, seq+1) < 0) {
							_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
							status = PAM_AUTHINFO_UNAVAIL;
						}
					break;

					case TAC_PLUS_AUTHEN_STATUS_GETDATA: {
						/* Get data from user with pam conversation */
						struct pam_message msg;
						struct pam_response *resp = NULL;
						int retval;
						char *user_data = NULL;

						/* set up conversation call */
						msg.msg_style = PAM_PROMPT_ECHO_OFF;
						msg.msg = malloc(100);
						strcpy((char *)msg.msg,msgstatus->server_msg);

						if ((retval = converse (pamh, 1, &msg, &resp)) != PAM_SUCCESS) {
							status = PAM_AUTHINFO_UNAVAIL;
						} else {
							if (resp != NULL) {
								if (resp->resp == NULL && (ctrl & PAM_TAC_DEBUG))
									_pam_log (LOG_DEBUG, "pam_sm_authenticate: NULL given by user for GETDATA request");

								user_data = resp->resp;
								resp->resp = NULL;
							} else {
								if (ctrl & PAM_TAC_DEBUG) {
									_pam_log (LOG_DEBUG, "pam_sm_authenticate: no error reported");
									_pam_log (LOG_DEBUG, "getting data from user - NULL returned!?");
								}
								return PAM_CONV_ERR;
							}

							/* AUTHEN/CONT with data */
							if (ctrl & PAM_TAC_DEBUG)
								_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

							if (tac_cont_send(tac_fd, user_data, ctrl, seq+1) < 0) {
								_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
								status = PAM_AUTHINFO_UNAVAIL;
							}
						}
						free(msg.msg);
					}
					break;

					case TAC_PLUS_AUTHEN_STATUS_GETUSER:
						/* AUTHEN/CONT with username */
						if (ctrl & PAM_TAC_DEBUG)
							_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

						if (tac_cont_send(tac_fd, user, ctrl, seq+1) < 0) {
							_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
							status = PAM_AUTHINFO_UNAVAIL;
						}
					break;
				}
			} while ( 	(status == TAC_PLUS_AUTHEN_STATUS_GETDATA) ||
						(status == TAC_PLUS_AUTHEN_STATUS_GETPASS) ||
						(status == TAC_PLUS_AUTHEN_STATUS_GETUSER)		);

            if (status != TAC_PLUS_AUTHEN_STATUS_PASS) {
                _pam_log (LOG_ERR, "auth failed: %d", status);
                status = PAM_AUTHTOK_ERR;
            } else {
                /* OK, we got authenticated; save the server that
                   accepted us for pam_sm_acct_mgmt and exit the loop */
                status = PAM_SUCCESS;
                active_server = tac_srv[srv_i];
                active_key = tac_srv_key[srv_i];
                close(tac_fd);
                break;
            }
        }
        close(tac_fd);
    }

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: exit with pam status: %i", __FUNCTION__, status);

    bzero (pass, strlen (pass));
    free(pass);
    pass = NULL;

    return status;
}    /* pam_sm_chauthtok */
Example #6
0
PAM_EXTERN
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
			int argc, const char **argv)
{
     const char *username;
     const char *password;
     const char *member = NULL;
     int retval = PAM_AUTH_ERR;
     int i;
    
     /* parse arguments */
     int ctrl = _pam_parse(argc, argv);

     /* Get the username */
     retval = pam_get_user(pamh, &username, NULL);
     if ((retval != PAM_SUCCESS) || (!username)) {
        if (ctrl & WINBIND_DEBUG_ARG)
            _pam_log(LOG_DEBUG,"can not get the username");
        return PAM_SERVICE_ERR;
     }
     
     retval = _winbind_read_password(pamh, ctrl, NULL, 
				     "Password: "******"Could not retrieve user's password");
	 return PAM_AUTHTOK_ERR;
     }
     
     if (ctrl & WINBIND_DEBUG_ARG) {

	     /* Let's not give too much away in the log file */

#ifdef DEBUG_PASSWORD
	 _pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
		  username, password);
#else
	 _pam_log(LOG_INFO, "Verify user `%s'", username);
#endif
     }

     /* Retrieve membership-string here */
     for ( i=0; i<argc; i++ ) {

	 if ((strncmp(argv[i], "require_membership_of", strlen("require_membership_of")) == 0) 
	     || (strncmp(argv[i], "require-membership-of", strlen("require-membership-of")) == 0)) {

	     char *p;
	     char *parm = strdup(argv[i]);

	     if ( (p = strchr( parm, '=' )) == NULL) {
	     	_pam_log(LOG_INFO, "no \"=\" delimiter for \"require_membership_of\" found\n");
		break;
	     }

	     member = strdup(p+1);
	 }
     }

     /* Now use the username to look up password */
     return winbind_auth_request(username, password, member, ctrl);
}
Example #7
0
static int set_filter(pam_handle_t *pamh, int flags, int ctrl
		      , const char **evp, const char *filtername)
{
    int status=-1;
    char terminal[TERMINAL_LEN];
    struct termio stored_mode;           /* initial terminal mode settings */
    int fd[2], child=0, child2=0, aterminal;

    if (filtername == NULL || *filtername != '/') {
	_pam_log(LOG_ALERT, "filtername not permitted; require full path");
	return PAM_ABORT;
    }

    if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) {
	aterminal = 0;
    } else {
	aterminal = 1;
    }

    if (aterminal) {

	/* open the master pseudo terminal */

	fd[0] = master(terminal);
	if (fd[0] < 0) {
	    _pam_log(LOG_CRIT,"no master terminal");
	    return PAM_AUTH_ERR;
	}

	/* set terminal into raw mode.. remember old mode so that we can
	   revert to it after the child has quit. */

	/* this is termio terminal handling... */

	if (ioctl(STDIN_FILENO, TCGETA, (char *) &stored_mode ) < 0) {
	    /* in trouble, so close down */
	    close(fd[0]);
	    _pam_log(LOG_CRIT, "couldn't copy terminal mode");
	    return PAM_ABORT;
	} else {
	    struct termio t_mode = stored_mode;

	    t_mode.c_iflag = 0;            /* no input control */
	    t_mode.c_oflag &= ~OPOST;      /* no ouput post processing */

	    /* no signals, canonical input, echoing, upper/lower output */
	    t_mode.c_lflag &= ~(ISIG|ICANON|ECHO|XCASE);
	    t_mode.c_cflag &= ~(CSIZE|PARENB);  /* no parity */
	    t_mode.c_cflag |= CS8;              /* 8 bit chars */

	    t_mode.c_cc[VMIN] = 1; /* number of chars to satisfy a read */
	    t_mode.c_cc[VTIME] = 0;          /* 0/10th second for chars */

	    if (ioctl(STDIN_FILENO, TCSETA, (char *) &t_mode) < 0) {
		close(fd[0]);
		_pam_log(LOG_WARNING, "couldn't put terminal in RAW mode");
		return PAM_ABORT;
	    }

	    /*
	     * NOTE: Unlike the stream socket case here the child
	     * opens the slave terminal as fd[1] *after* the fork...
	     */
	}
    } else {

	/*
	 * not a terminal line so just open a stream socket fd[0-1]
	 * both set...
	 */

	if ( socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0 ) {
	    _pam_log(LOG_CRIT,"couldn't open a stream pipe");
	    return PAM_ABORT;
	}
    }

    /* start child process */

    if ( (child = fork()) < 0 ) {

	_pam_log(LOG_WARNING,"first fork failed");
	if (aterminal) {
	    (void) ioctl(STDIN_FILENO, TCSETA, (char *) &stored_mode);
	}

	return PAM_AUTH_ERR;
    }

    if ( child == 0 ) {                  /* child process *is* application */

	if (aterminal) {

	    /* close the controlling tty */

#if defined(__hpux) && defined(O_NOCTTY)
	    int t = open("/dev/tty", O_RDWR|O_NOCTTY);
#else
	    int t = open("/dev/tty",O_RDWR);
	    if (t > 0) {
		(void) ioctl(t, TIOCNOTTY, NULL);
		close(t);
	    }
#endif /* defined(__hpux) && defined(O_NOCTTY) */

	    /* make this process it's own process leader */
	    if (setsid() == -1) {
		_pam_log(LOG_WARNING,"child cannot become new session");
		return PAM_ABORT;
	    }

	    /* find slave's name */
	    terminal[5] = 't';             /* want to open slave terminal */
	    fd[1] = open(terminal, O_RDWR);
	    close(fd[0]);      /* process is the child -- uses line fd[1] */

	    if (fd[1] < 0) {
		_pam_log(LOG_WARNING,"cannot open slave terminal; %s"
			 ,terminal);
		return PAM_ABORT;
	    }

	    /* initialize the child's terminal to be the way the
	       parent's was before we set it into RAW mode */

	    if (ioctl(fd[1], TCSETA, (char *) &stored_mode) < 0) {
		_pam_log(LOG_WARNING,"cannot set slave terminal mode; %s"
			 ,terminal);
		close(fd[1]);
		return PAM_ABORT;
	    }

	} else {

	    /* nothing to do for a simple stream socket */

	}

	/* re-assign the stdin/out to fd[1] <- (talks to filter). */

	if ( dup2(fd[1],STDIN_FILENO) != STDIN_FILENO ||
	     dup2(fd[1],STDOUT_FILENO) != STDOUT_FILENO ||
	     dup2(fd[1],STDERR_FILENO) != STDERR_FILENO )  {
	    _pam_log(LOG_WARNING
		     ,"unable to re-assign STDIN/OUT/ERR...'s");
	    close(fd[1]);
	    return PAM_ABORT;
	}

	/* make sure that file descriptors survive 'exec's */

	if ( fcntl(STDIN_FILENO, F_SETFD, 0) ||
	     fcntl(STDOUT_FILENO,F_SETFD, 0) ||
	     fcntl(STDERR_FILENO,F_SETFD, 0) ) {
	    _pam_log(LOG_WARNING
		     ,"unable to re-assign STDIN/OUT/ERR...'s");
	    return PAM_ABORT;
	}

	/* now the user input is read from the parent/filter: forget fd */

	close(fd[1]);

	/* the current process is now aparently working with filtered
	   stdio/stdout/stderr --- success! */

	return PAM_SUCCESS;
    }

    /*
     * process is the parent here. So we can close the application's
     * input/output
     */

    close(fd[1]);

    /* Clear out passwords... there is a security problem here in
     * that this process never executes pam_end.  Consequently, any
     * other sensitive data in this process is *not* explicitly
     * overwritten, before the process terminates */

    (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
    (void) pam_set_item(pamh, PAM_OLDAUTHTOK, NULL);

    /* fork a copy of process to run the actual filter executable */

    if ( (child2 = fork()) < 0 ) {

	_pam_log(LOG_WARNING,"filter fork failed");
	child2 = 0;

    } else if ( child2 == 0 ) {              /* exec the child filter */

	if ( dup2(fd[0],APPIN_FILENO) != APPIN_FILENO ||
	     dup2(fd[0],APPOUT_FILENO) != APPOUT_FILENO ||
	     dup2(fd[0],APPERR_FILENO) != APPERR_FILENO )  {
	    _pam_log(LOG_WARNING
		     ,"unable to re-assign APPIN/OUT/ERR...'s");
	    close(fd[0]);
	    exit(1);
	}

	/* make sure that file descriptors survive 'exec's */

	if ( fcntl(APPIN_FILENO, F_SETFD, 0) == -1 ||
	     fcntl(APPOUT_FILENO,F_SETFD, 0) == -1 ||
	     fcntl(APPERR_FILENO,F_SETFD, 0) == -1 ) {
	    _pam_log(LOG_WARNING
		     ,"unable to retain APPIN/OUT/ERR...'s");
	    close(APPIN_FILENO);
	    close(APPOUT_FILENO);
	    close(APPERR_FILENO);
	    exit(1);
	}

	/* now the user input is read from the parent through filter */

	execle(filtername, "<pam_filter>", NULL, evp);

	/* getting to here is an error */

	_pam_log(LOG_ALERT, "filter: %s, not executable", filtername);

    } else {           /* wait for either of the two children to exit */

	while (child && child2) {    /* loop if there are two children */
	    int lstatus=0;
	    int chid;

	    chid = wait(&lstatus);
	    if (chid == child) {

		if (WIFEXITED(lstatus)) {            /* exited ? */
		    status = WEXITSTATUS(lstatus);
		} else if (WIFSIGNALED(lstatus)) {   /* killed ? */
		    status = -1;
		} else
		    continue;             /* just stopped etc.. */
		child = 0;        /* the child has exited */

	    } else if (chid == child2) {
		/*
		 * if the filter has exited. Let the child die
		 * naturally below
		 */
		if (WIFEXITED(lstatus) || WIFSIGNALED(lstatus))
		    child2 = 0;
	    } else {

		_pam_log(LOG_ALERT
			 ,"programming error <chid=%d,lstatus=%x>: "
			 __FILE__ " line %d"
			 , lstatus, __LINE__ );
		child = child2 = 0;
		status = -1;

	    }
	}
    }

    close(fd[0]);

    /* if there is something running, wait for it to exit */

    while (child || child2) {
	int lstatus=0;
	int chid;

	chid = wait(&lstatus);

	if (child && chid == child) {

	    if (WIFEXITED(lstatus)) {            /* exited ? */
		status = WEXITSTATUS(lstatus);
	    } else if (WIFSIGNALED(lstatus)) {   /* killed ? */
		status = -1;
	    } else
		continue;             /* just stopped etc.. */
	    child = 0;        /* the child has exited */

	} else if (child2 && chid == child2) {

	    if (WIFEXITED(lstatus) || WIFSIGNALED(lstatus))
		child2 = 0;

	} else {

	    _pam_log(LOG_ALERT
		     ,"programming error <chid=%d,lstatus=%x>: "
		     __FILE__ " line %d"
		     , lstatus, __LINE__ );
	    child = child2 = 0;
	    status = -1;

	}
    }

    if (aterminal) {
	/* reset to initial terminal mode */
	(void) ioctl(STDIN_FILENO, TCSETA, (char *) &stored_mode);
    }

    if (ctrl & FILTER_DEBUG) {
	_pam_log(LOG_DEBUG,"parent process exited");      /* clock off */
    }

    /* quit the parent process, returning the child's exit status */

    exit(status);
}
Example #8
0
/* authenticates user on remote TACACS+ server
 * returns PAM_SUCCESS if the supplied username and password
 * pair is valid 
 */
PAM_EXTERN 
int pam_sm_authenticate (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    int srv_i;
    int tac_fd;
    int status = PAM_AUTH_ERR;
    int seq = 0;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);
  
    /* uwzgledniac PAM_DISALLOW_NULL_AUTHTOK */

    retval = tacacs_get_password (pamh, flags, ctrl, &pass);

    if (retval != PAM_SUCCESS || pass == NULL || *pass == '\0') {
        _pam_log (LOG_ERR, "unable to obtain password");
        return PAM_CRED_INSUFFICIENT;
    }

    retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
    if (retval != PAM_SUCCESS) {
        _pam_log (LOG_ERR, "unable to set password");
        return PAM_CRED_INSUFFICIENT;
    }

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: password obtained", __FUNCTION__);

    tty = _pam_get_terminal(pamh);
    if (!strncmp (tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    /* Attempt server connect */
    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        status = TAC_PLUS_AUTHEN_STATUS_FAIL;
        if (ctrl & PAM_TAC_DEBUG)
            _pam_log (LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
        if (tac_fd < 0) {
            _pam_log (LOG_ERR, "connection failed srv %d: %m", srv_i);
            if (srv_i == tac_srv_no-1) {
                _pam_log (LOG_ERR, "no more servers to connect");
                return PAM_AUTHINFO_UNAVAIL;
            }
            continue;
        }

        /* Send AUTHEN/START */
        if (tac_authen_send(tac_fd, user, pass, tty, r_addr, TAC_PLUS_AUTHEN_LOGIN, ctrl) < 0) {
            _pam_log (LOG_ERR, "error sending auth req to TACACS+ server");
            status = PAM_AUTHINFO_UNAVAIL;
        } else {
        	/* Read AUTHEN/REPLY and act on status */
        	struct msg_status *msgstatus = malloc(sizeof(msg_status));

            do
			{
            	tac_authen_read(msgstatus, tac_fd, ctrl, &seq);
        		status = msgstatus->status;

            	switch (status) {
            		case TAC_PLUS_AUTHEN_STATUS_GETPASS:
            			/* AUTHEN/CONT with password */
						if (ctrl & PAM_TAC_DEBUG)
							_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

						if (tac_cont_send(tac_fd, pass, ctrl, seq+1) < 0) {
							_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
							status = PAM_MAXTRIES;
						}
            		break;

            		case TAC_PLUS_AUTHEN_STATUS_GETDATA: {
            			/* The only GETDATA request should be if the user's password
            			 * has expired and ACS is requesting a new password
            			 *
            			 * Check if a conversation function has been set and either
            			 * return a PAM_AUTHTOK_EXPIRED or start a conversation
            			 * with the user for to change the password
            			 */
            			if (!strcmp(tty,"http")) {
            				status = PAM_NEW_AUTHTOK_REQD;
            				if (ctrl & PAM_TAC_DEBUG)
            					_pam_log (LOG_DEBUG, "%s: expired", __FUNCTION__);
            			} else {

							/* Get data from user with pam conversation */
							struct pam_message msg;
							struct pam_response *resp = NULL;
							int retval;
							char *user_data = NULL;

							/* set up conversation call */
							msg.msg_style = PAM_PROMPT_ECHO_OFF;
							msg.msg = malloc(100);
							strcpy((char *)msg.msg,msgstatus->server_msg);

							if ((retval = converse (pamh, 1, &msg, &resp)) != PAM_SUCCESS) {
								status = PAM_AUTHINFO_UNAVAIL;
							} else {
								if (resp != NULL) {
									if (resp->resp == NULL && (ctrl & PAM_TAC_DEBUG))
										_pam_log (LOG_DEBUG, "pam_sm_authenticate: NULL given by user for GETDATA request");

									user_data = resp->resp;
									resp->resp = NULL;
								} else {
									if (ctrl & PAM_TAC_DEBUG) {
										_pam_log (LOG_DEBUG, "pam_sm_authenticate: no error reported");
										_pam_log (LOG_DEBUG, "getting data from user - NULL returned!?");
									}
									return PAM_CONV_ERR;
								}

								/* AUTHEN/CONT with data */
								if (ctrl & PAM_TAC_DEBUG)
									_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

								if (tac_cont_send(tac_fd, user_data, ctrl, seq+1) < 0) {
									_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
									status = PAM_AUTHINFO_UNAVAIL;
								}
							}
							free(msg.msg);
            			}
            		}
            		break;

            		case TAC_PLUS_AUTHEN_STATUS_GETUSER:
            			/* AUTHEN/CONT with username */
            			if (ctrl & PAM_TAC_DEBUG)
							_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

						if (tac_cont_send(tac_fd, user, ctrl, seq+1) < 0) {
							_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
							status = PAM_AUTHINFO_UNAVAIL;
						}
            		break;
            	}
            } while ( 	(status == TAC_PLUS_AUTHEN_STATUS_GETDATA) ||
            			(status == TAC_PLUS_AUTHEN_STATUS_GETPASS) ||
            			(status == TAC_PLUS_AUTHEN_STATUS_GETUSER)		);

            if (ctrl & PAM_TAC_DEBUG)
            	_pam_log (LOG_DEBUG, "%s: out of while loop status=%d", __FUNCTION__,status);

            if (status == TAC_PLUS_AUTHEN_STATUS_PASS) {
            	/* OK, we got authenticated; save the server that
				   accepted us for pam_sm_acct_mgmt and exit the loop */
				status = PAM_SUCCESS;
				active_server = tac_srv[srv_i];
				active_key = tac_srv_key[srv_i];
            } else if (status != PAM_NEW_AUTHTOK_REQD) {
                _pam_log (LOG_ERR, "auth failed: %d", status);
                status = PAM_AUTH_ERR;
            }
        }
        close(tac_fd);

        /* TODO: Allow time for tac server to reply
         * TODO: Check if reply received before connecting to next server
         */
    }

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: exit with pam status: %i", __FUNCTION__, status);

    bzero (pass, strlen (pass));
    free(pass);
    pass = NULL;

    return status;
}    /* pam_sm_authenticate */
static int
pam_iruserok(pam_handle_t *pamh,
	 struct _options *opts, U32 raddr, int superuser,
	 const char *ruser, const char *luser, const char *rhost)
{
    const char *cp;
    struct stat sbuf;
    struct passwd *pwd;
    FILE *hostf;
    uid_t uid;
    int answer;
    char pbuf[MAXPATHLEN];               /* potential buffer overrun */

    if ((!superuser||opts->opt_hosts_equiv_rootok) && !opts->opt_no_hosts_equiv ) {

	/* try to open system hosts.equiv file */
	hostf = fopen (_PATH_HEQUIV, "r");
	if (hostf) {
	    answer = __ivaliduser(pamh, opts, hostf, raddr, luser
				  , ruser, rhost);
	    (void) fclose(hostf);
	    if (answer == 0)
		return 0;      /* remote host is equivalent to localhost */
	} /* else {
	    No hosts.equiv file on system.
	} */
    }
    
    if ( opts->opt_no_rhosts )
	return 1;

    /*
     * Identify user's local .rhosts file
     */

    pwd = _pammodutil_getpwnam(pamh, luser);
    if (pwd == NULL) {
	/* 
	 * luser is assumed to be valid because of an earlier check for uid = 0
	 * we don't log this error twice. However, this shouldn't happen !
	 * --cristiang 
	 */
	return(1);
    }

    /* check for buffer overrun */
    if (strlen(pwd->pw_dir) + sizeof(USER_RHOSTS_FILE) + 2 >= MAXPATHLEN) {
	if (opts->opt_debug)
	    _pam_log(LOG_DEBUG,"home directory for `%s' is too long", luser);
	return 1;                               /* to dangerous to try */
    }

    (void) strcpy(pbuf, pwd->pw_dir);
    (void) strcat(pbuf, USER_RHOSTS_FILE);

    /*
     * Change effective uid while _reading_ .rhosts. (not just
     * opening).  If root and reading an NFS mounted file system,
     * can't read files that are 0600 as .rhosts files should be.
     */

    /* We are root, this will not fail */
#ifdef linux
    /* If we are on linux the better way is setfsuid */
    uid = setfsuid(pwd->pw_uid);
    hostf = fopen(pbuf, "r");
#else
    uid = geteuid();
    (void) seteuid(pwd->pw_uid);
    hostf = fopen(pbuf, "r");
#endif

    if (hostf == NULL) {
        if (opts->opt_debug)
	    _pam_log(LOG_DEBUG,"Could not open %s file",pbuf);
	answer = 1;
	goto exit_function;
    }

    /*
     * If not a regular file, or is owned by someone other than
     * user or root or if writeable by anyone but the owner, quit.
     */

    cp = NULL;
    if (lstat(pbuf, &sbuf) < 0 || !S_ISREG(sbuf.st_mode))
	cp = ".rhosts not regular file";
    else if (fstat(fileno(hostf), &sbuf) < 0)
	cp = ".rhosts fstat failed";
    else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
	cp = "bad .rhosts owner";
    else if (sbuf.st_mode & S_IWOTH)
	cp = ".rhosts writable by other!";
    else if (sbuf.st_mode & S_IWGRP) {

	/* private group caveat */
	if (opts->opt_private_group) {
	    struct group *grp = getgrgid(sbuf.st_gid);

	    if (NULL == grp || NULL == grp->gr_name
		|| strcmp(luser,grp->gr_name)) {
		cp = ".rhosts writable by public group";
	    } else if (grp->gr_mem) {
		int gcount;

		/* require at most one member (luser) of this group */
		for (gcount=0; grp->gr_mem[gcount]; ++gcount) {
		    if (strcmp(grp->gr_mem[gcount], luser)) {
			gcount = -1;
			break;
		    }
		}
		if (gcount < 0) {
		    cp = ".rhosts writable by other members of group";
		}
	    }
	} else {
	    cp = ".rhosts writable by group";
	}

    } /* It is _NOT_ safe to append an else here...  Do so prior to
       * S_IWGRP check */

    /* If there were any problems, quit. */
    if (cp) {
	opts->last_error = cp;
	answer = 1;
	goto exit_function;
    }

    answer = __ivaliduser (pamh, opts, hostf, raddr, luser, ruser, rhost);

exit_function:
    /*
     * Go here to exit after the fsuid/euid has been adjusted so that
     * they are reset before we exit.
     */

#ifdef linux
    setfsuid(uid);
#else
    (void)seteuid(uid);
#endif

    if (hostf != NULL)
        (void) fclose(hostf);

    return answer;
}
Example #10
0
static int _pam_auth_rhosts (pam_handle_t *pamh,
			     int flags, 
			     int argc,
			     const char **argv) 
{
    int retval;
    const char *luser = NULL;
    const char *ruser = NULL, *rhost = NULL;
    struct _options opts;
    int as_root = 0;

    /*
     * Look at the options and set the flags accordingly.
     */
    memset (&opts, 0, sizeof (opts));
    set_parameters (&opts, flags, argc, argv);
    /*
     * Obtain the parameters for the various items
     */
    for (;;) {                         /* abuse loop to avoid goto */

	/* get the remotehost */
	D(("getting rhost"));
	retval = pam_get_rhost(pamh, &rhost, NULL);
	(void) pam_set_item(pamh, PAM_RHOST, rhost);
	if (retval != PAM_SUCCESS) {
	    if (opts.opt_debug) {
		_pam_log(LOG_DEBUG, "could not get the remote host name");
	    }
	    break;
	}

	/* get the remote user */
	D(("getting ruser"));
	retval = pam_get_ruser(pamh, &ruser, NULL);
	(void) pam_set_item(pamh, PAM_RUSER, ruser);
	if (retval != PAM_SUCCESS) {
	    if (opts.opt_debug)
		_pam_log(LOG_DEBUG, "could not get the remote username");
	    break;
	}

	/* get the local user */
	D(("getting user"));
	retval = pam_get_user(pamh, &luser, NULL);
	if (retval != PAM_SUCCESS) {
	    if (opts.opt_debug)
		_pam_log(LOG_DEBUG, "could not determine name of local user");
	    break;
	}

	if (opts.superuser && !strcmp(opts.superuser, luser)) {
	    as_root = 1;
	}

	/* check if the luser uid == 0... --cristiang */
	if (! opts.opt_no_uid_check) {
	    struct passwd *luser_pwd;

	    luser_pwd = _pammodutil_getpwnam(pamh, luser);
	    if (luser_pwd == NULL) {
		if (opts.opt_debug)
		    _pam_log(LOG_DEBUG, "user '%s' unknown to this system",
			     luser);
		retval = PAM_AUTH_ERR;
		break;
	    }
	    if (luser_pwd->pw_uid == 0)
		as_root = 1;
	    luser_pwd = NULL;                                   /* forget */
	}
/*
 * Validate the account information.
 */
	if (pam_ruserok (pamh, &opts, rhost, as_root, ruser, luser) != 0) {
	    if ( !opts.opt_suppress ) {
		_pam_log(LOG_WARNING, "denied to %s@%s as %s: %s",
			 ruser, rhost, luser, (opts.last_error==NULL) ?
			 "access not allowed":opts.last_error);
	    }
	    retval = PAM_AUTH_ERR;
	} else {
	    _pam_log(LOG_NOTICE, "allowed to %s@%s as %s",
                     ruser, rhost, luser);
	}
	break;
    }

    return retval;
}
Example #11
0
/* no-op function for future use */
PAM_EXTERN
int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    const void *pam_pass = NULL;
    int srv_i;
    int tac_fd, status, msg, communicating;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse(argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    syslog(LOG_DEBUG, "%s(flags=%d, argc=%d)", __func__, flags, argc);

    if (   (pam_get_item(pamh, PAM_OLDAUTHTOK, &pam_pass) == PAM_SUCCESS)
        && (pam_pass != NULL) ) {
         if ((pass = strdup(pam_pass)) == NULL)
              return PAM_BUF_ERR;
    } else {
        pass = strdup("");
    }
    
    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;
    
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);

    tty = _pam_get_terminal(pamh);
    if (!strncmp(tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    if (PAM_SILENT == (flags & PAM_SILENT)) {
        status = PAM_AUTHTOK_ERR;
        goto finish;
    }

    status = PAM_TRY_AGAIN;
    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        if (ctrl & PAM_TAC_DEBUG)
            syslog(LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, NULL, tac_timeout);
        if (tac_fd < 0) {
            _pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i);
            continue;
        }
        if (PAM_PRELIM_CHECK == (flags & PAM_PRELIM_CHECK)) {
            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                syslog(LOG_DEBUG, "%s: finishing PAM_PRELIM_CHECK with srv %d",
                       __FUNCTION__, srv_i);

            close(tac_fd);
            status = PAM_SUCCESS;
            goto finish;
        }

        if (tac_authen_send(tac_fd, user, "", tty, r_addr, TAC_PLUS_AUTHEN_CHPASS) < 0) {
            close(tac_fd);
            _pam_log(LOG_ERR, "error sending auth req to TACACS+ server");
            continue;
        }
        communicating = 1;
        while (communicating) {
            struct areply re = { .attr = NULL, .msg = NULL, status = 0, flags = 0 };
            struct pam_message conv_msg = { .msg_style = 0, .msg = NULL };
            struct pam_response *resp = NULL;

            msg = tac_authen_read(tac_fd, &re);

            if (NULL != re.msg) {
                conv_msg.msg = re.msg;
            }

            /* talk the protocol */
            switch (msg) {
                case TAC_PLUS_AUTHEN_STATUS_PASS:
                    /* success */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_PASS");

                    if (NULL != conv_msg.msg) {
                        int retval = -1;

                        conv_msg.msg_style = PAM_TEXT_INFO;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "send msg=\"%s\"", conv_msg.msg);
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d",
                                     __FUNCTION__, conv_msg.msg, retval);
                        }

                    }
                    status = PAM_SUCCESS;
                    communicating = 0;

                    active_server.addr = tac_srv[srv_i].addr;
                    active_server.key = tac_srv[srv_i].key;

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i);

                    break;

                case TAC_PLUS_AUTHEN_STATUS_FAIL:
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FAIL");

                    if (NULL != conv_msg.msg) {
                        int retval = -1;

                        conv_msg.msg_style = PAM_ERROR_MSG;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "send msg=\"%s\"", conv_msg.msg);
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d",
                                     __FUNCTION__, conv_msg.msg, retval);
                        }

                    }
                    status = PAM_AUTHTOK_ERR;
                    communicating = 0;

                    _pam_log(LOG_ERR, "chauthtok failed: %d", msg);

                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETDATA:
                    if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETDATA");

                    if (NULL != conv_msg.msg) {
                        int retval = -1;
                        int echo_off = (0x1 == (re.flags & 0x1));
                        
                        conv_msg.msg_style = echo_off ? PAM_PROMPT_ECHO_OFF : PAM_PROMPT_ECHO_ON;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG)) 
                                syslog(LOG_DEBUG, "sent msg=\"%s\", resp=\"%s\"",
                                       conv_msg.msg, resp->resp);

                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "%s: calling tac_cont_send", __FUNCTION__);

                            if (0 > tac_cont_send_seq(tac_fd, resp->resp, re.seq_no + 1)) {
                                _pam_log(LOG_ERR, "error sending continue req to TACACS+ server");
                                communicating = 0;
                            }
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d",
                                     __FUNCTION__, conv_msg.msg, retval);
                            communicating = 0;
                        }
                    }
                    else { 
                        syslog(LOG_ERR, "GETDATA response with no message, returning PAM_TRY_AGAIN");
                        communicating = 0;
                    }

                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETUSER:
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETUSER");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETPASS:
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETPASS");

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: calling tac_cont_send", __FUNCTION__);

                    if (tac_cont_send(tac_fd, pass) < 0) {
                        _pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
                        communicating = 0;
                        break;
                    }
                    /* continue the while loop; go read tac response */
                    break;

                case TAC_PLUS_AUTHEN_STATUS_RESTART:
                    /* try it again */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_RESTART");

                    /*
                     * not implemented
                     * WdJ: I *think* you can just do tac_authen_send(user, pass) again
                     *      but I'm not sure
                     */
                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_ERROR:
                    /* server has problems */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_ERROR");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_FOLLOW:
                    /* server tells to try a different server address */
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FOLLOW");

                    communicating = 0;
                    break;

                default:
                    if (msg < 0) {
                        /* connection error */
                        communicating = 0;
                        if (ctrl & PAM_TAC_DEBUG)
                            syslog(LOG_DEBUG, "error communicating with tacacs server");
                        break;
                    }

                    /* unknown response code */
                    communicating = 0;
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: unknown response 0x%02x", msg);
            }

            if (NULL != resp) {
                free(resp->resp);
                free(resp);
            }

            free(re.msg);

        }    /* end while(communicating) */
        close(tac_fd);

        if (status == PAM_SUCCESS || status == PAM_AUTHTOK_ERR)
            break;
    }

finish:
    if (status != PAM_SUCCESS && status != PAM_AUTHTOK_ERR)
        _pam_log(LOG_ERR, "no more servers to connect");

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: exit with pam status: %d", __FUNCTION__, status);

    if (NULL != pass) {
        bzero(pass, strlen(pass));
        free(pass);
        pass = NULL;
    }

    return status;
}    /* pam_sm_chauthtok */
#endif


#ifdef PAM_STATIC
struct pam_module _pam_tacplus_modstruct {
    "pam_tacplus",
    pam_sm_authenticate,
    pam_sm_setcred,
    pam_sm_acct_mgmt,
    pam_sm_open_session,
    pam_sm_close_session,
#ifdef PAM_SM_PASSWORD
    pam_sm_chauthtok
#else
    NULL
#endif
};
Example #12
0
/* authenticates user on remote TACACS+ server
 * returns PAM_SUCCESS if the supplied username and password
 * pair is valid
 */
PAM_EXTERN
int pam_sm_authenticate (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    int srv_i;
    int tac_fd, status, msg, communicating;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse(argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)",
            __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);

    retval = tacacs_get_password (pamh, flags, ctrl, &pass);
    if (retval != PAM_SUCCESS || pass == NULL || *pass == '\0') {
        _pam_log(LOG_ERR, "unable to obtain password");
        return PAM_CRED_INSUFFICIENT;
    }

    retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
    if (retval != PAM_SUCCESS) {
        _pam_log(LOG_ERR, "unable to set password");
        return PAM_CRED_INSUFFICIENT;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: password obtained", __FUNCTION__);

    tty = _pam_get_terminal(pamh);
    if (!strncmp(tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    status = PAM_AUTHINFO_UNAVAIL;
    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        if (ctrl & PAM_TAC_DEBUG)
            syslog(LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, NULL, tac_timeout);
        if (tac_fd < 0) {
            _pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i);
            continue;
        }
        if (tac_authen_send(tac_fd, user, pass, tty, r_addr, TAC_PLUS_AUTHEN_LOGIN) < 0) {
            close(tac_fd);
            _pam_log(LOG_ERR, "error sending auth req to TACACS+ server");
            continue;
        }
        communicating = 1;
        while (communicating) {
            struct areply re = { .attr = NULL, .msg = NULL, status = 0, flags = 0 };
            struct pam_message conv_msg = { .msg_style = 0, .msg = NULL };
            struct pam_response *resp = NULL;

            msg = tac_authen_read(tac_fd, &re);

            if (NULL != re.msg) {
                conv_msg.msg = re.msg;
            }

            /* talk the protocol */
            switch (msg) {
                case TAC_PLUS_AUTHEN_STATUS_PASS:
                    /* success */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_PASS");
  
                    if (NULL != conv_msg.msg) {
                        int retval = -1;

                        conv_msg.msg_style = PAM_TEXT_INFO;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "send msg=\"%s\"", conv_msg.msg);
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d",
                                     __FUNCTION__, conv_msg.msg, retval);
                        }

                    }
                    status = PAM_SUCCESS;
                    communicating = 0;
                    active_server.addr = tac_srv[srv_i].addr;
                    active_server.key = tac_srv[srv_i].key;

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i);

                    break;

                case TAC_PLUS_AUTHEN_STATUS_FAIL:
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FAIL");

                    if (NULL != conv_msg.msg) {
                        int retval = -1;

                        conv_msg.msg_style = PAM_ERROR_MSG;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "send msg=\"%s\"", conv_msg.msg);
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d",
                                     __FUNCTION__, conv_msg.msg, retval);
                        }

                    }
                    status = PAM_AUTH_ERR;
                    communicating = 0;

                    _pam_log(LOG_ERR, "auth failed: %d", msg);

                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETDATA:
                    if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETDATA");

                    if (NULL != conv_msg.msg) {
                        int retval = -1;
                        int echo_off = (0x1 == (re.flags & 0x1));
                        
                        conv_msg.msg_style = echo_off ? PAM_PROMPT_ECHO_OFF : PAM_PROMPT_ECHO_ON;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG)) 
                                syslog(LOG_DEBUG, "sent msg=\"%s\", resp=\"%s\"",
                                       conv_msg.msg, resp->resp);

                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "%s: calling tac_cont_send", __FUNCTION__);

                            if (0 > tac_cont_send_seq(tac_fd, resp->resp, re.seq_no + 1)) {
                                _pam_log(LOG_ERR, "error sending continue req to TACACS+ server");
                                status = PAM_AUTH_ERR;
                                communicating = 0;
                            }
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d (%s)",
                                     __FUNCTION__, conv_msg.msg, retval, pam_strerror(pamh, retval));
                            status = PAM_AUTH_ERR;
                            communicating = 0;
                        }
                    }
                    else { 
                        syslog(LOG_ERR, "GETDATA response with no message, returning PAM_AUTH_ERR");

                        status = PAM_AUTH_ERR;
                        communicating = 0;
                    }

                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETUSER:
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETUSER");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETPASS:
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETPASS");

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

                    if (tac_cont_send(tac_fd, pass) < 0) {
                        _pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
                        communicating = 0;
                    }
                    /* continue the while loop; go read tac response */
                    break;

                case TAC_PLUS_AUTHEN_STATUS_RESTART:
                    /* try it again */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_RESTART");

                    /*
                     * not implemented
                     * WdJ: I *think* you can just do tac_authen_send(user, pass) again
                     *      but I'm not sure
                     */
                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_ERROR:
                    /* server has problems */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_ERROR");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_FOLLOW:
                    /* server tells to try a different server address */
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FOLLOW");

                    communicating = 0;
                    break;

                default:
                    if (msg < 0) {
                        /* connection error */
                        communicating = 0;
                        if (ctrl & PAM_TAC_DEBUG)
                            syslog(LOG_DEBUG, "error communicating with tacacs server");
                        break;
                    }

                    /* unknown response code */
                    communicating = 0;
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: unknown response 0x%02x", msg);
            }

            if (NULL != resp) {
                free(resp->resp);
                free(resp);
            }
                
            free(re.msg);

        }    /* end while(communicating) */
        close(tac_fd);

        if (status == PAM_SUCCESS || status == PAM_AUTH_ERR)
            break;
    }
    if (status != PAM_SUCCESS && status != PAM_AUTH_ERR)
        _pam_log(LOG_ERR, "no more servers to connect");

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: exit with pam status: %d", __FUNCTION__, status);

    if (NULL != pass) {
        bzero(pass, strlen (pass));
        free(pass);
        pass = NULL;
    }

    return status;
}    /* pam_sm_authenticate */


/* no-op function to satisfy PAM authentication module */
PAM_EXTERN
int pam_sm_setcred (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    return PAM_SUCCESS;
}    /* pam_sm_setcred */


/* authorizes user on remote TACACS+ server, i.e. checks
 * his permission to access requested service
 * returns PAM_SUCCESS if the service is allowed
 */
PAM_EXTERN
int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int retval, ctrl, status=PAM_AUTH_ERR;
    char *user;
    char *tty;
    char *r_addr;
    struct areply arep;
    struct tac_attrib *attr = NULL;
    int tac_fd;

    user = tty = r_addr = NULL;

    /* this also obtains service name for authorization
       this should be normally performed by pam_get_item(PAM_SERVICE)
       but since PAM service names are incompatible TACACS+
       we have to pass it via command line argument until a better
       solution is found ;) */
    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: username obtained [%s]", __FUNCTION__, user);

    tty = _pam_get_terminal(pamh);
    if(!strncmp(tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: tty obtained [%s]", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: rhost obtained [%s]", __FUNCTION__, r_addr);

    /* checks if user has been successfully authenticated
       by TACACS+; we cannot solely authorize user if it hasn't
       been authenticated or has been authenticated by method other
       than TACACS+ */
    if(active_server.addr == NULL) {
        _pam_log (LOG_ERR, "user not authenticated by TACACS+");
        return PAM_AUTH_ERR;
    }
    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: active server is [%s]", __FUNCTION__,
            tac_ntop(active_server.addr->ai_addr));

    /* checks for specific data required by TACACS+, which should
       be supplied in command line  */
    if(!*tac_service) {
        _pam_log (LOG_ERR, "SM: TACACS+ service type not configured");
        return PAM_AUTH_ERR;
    }
    if(tac_protocol == NULL || !*tac_protocol) {
        _pam_log (LOG_ERR, "SM: TACACS+ protocol type not configured (IGNORED)");
    }

    tac_add_attrib(&attr, "service", tac_service);
    if(tac_protocol != NULL && tac_protocol[0] != '\0')
      tac_add_attrib(&attr, "protocol", tac_protocol);

    tac_fd = tac_connect_single(active_server.addr, active_server.key, NULL, tac_timeout);
    if(tac_fd < 0) {
        _pam_log (LOG_ERR, "TACACS+ server unavailable");
        if(arep.msg != NULL)
            free (arep.msg);

        close(tac_fd);
        return PAM_AUTH_ERR;
    }

    retval = tac_author_send(tac_fd, user, tty, r_addr, attr);

    tac_free_attrib(&attr);

    if(retval < 0) {
        _pam_log (LOG_ERR, "error getting authorization");
        if(arep.msg != NULL)
            free (arep.msg);

        close(tac_fd);
        return PAM_AUTH_ERR;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: sent authorization request", __FUNCTION__);

    tac_author_read(tac_fd, &arep);

    if(arep.status != AUTHOR_STATUS_PASS_ADD &&
        arep.status != AUTHOR_STATUS_PASS_REPL) {

        _pam_log (LOG_ERR, "TACACS+ authorisation failed for [%s]", user);
        if(arep.msg != NULL)
            free (arep.msg);

        close(tac_fd);
        return PAM_PERM_DENIED;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: user [%s] successfully authorized", __FUNCTION__, user);

    status = PAM_SUCCESS;

    attr = arep.attr;
    while (attr != NULL)  {
        char attribute[attr->attr_len];
        char value[attr->attr_len];
        char *sep;

        sep = index(attr->attr, '=');
        if(sep == NULL)
            sep = index(attr->attr, '*');
        if(sep != NULL) {
            bcopy(attr->attr, attribute, attr->attr_len-strlen(sep));
            attribute[attr->attr_len-strlen(sep)] = '\0';
            bcopy(sep, value, strlen(sep));
            value[strlen(sep)] = '\0';

            size_t i;
            for (i = 0; attribute[i] != '\0'; i++) {
                attribute[i] = toupper(attribute[i]);
                if (attribute[i] == '-')
                    attribute[i] = '_';
            }

            if (ctrl & PAM_TAC_DEBUG)
                syslog(LOG_DEBUG, "%s: returned attribute `%s%s' from server", __FUNCTION__, attribute, value);

            /* make returned attributes available for other PAM modules via PAM environment */
            if (pam_putenv(pamh, strncat(attribute, value, strlen(value))) != PAM_SUCCESS)
                syslog(LOG_WARNING, "%s: unable to set PAM environment", __FUNCTION__);

        } else {
            syslog(LOG_WARNING, "%s: invalid attribute `%s', no separator", __FUNCTION__, attr->attr);
        }
        attr = attr->next;
    }

    /* free returned attributes */
    if(arep.attr != NULL)
        tac_free_attrib(&arep.attr);

    if(arep.msg != NULL)
        free (arep.msg);

    close(tac_fd);

    return status;
}    /* pam_sm_acct_mgmt */
Example #13
0
static int
exec_file(pam_handle_t *pamh, char **argv, const char *logfile)
{
	pid_t pid, rc;
	int p[2];
	char buf[1024];
	long ttl;
	time_t start;
	int i, status, intr;
	fd_set rd;
	struct timeval tv;
	size_t total = 0;
	
	if (pipe(p)) {
		_pam_log(LOG_ERR, "pipe: %s", strerror(errno));
		return PAM_SYSTEM_ERR;
	}
		
	pid = fork();
	if (pid == -1) {
		close(p[0]);
		close(p[1]);
		_pam_log(LOG_ERR, "fork: %s", strerror(errno));
		return PAM_SYSTEM_ERR;
	}
	
	if (pid == 0) {		
		/* child */
		if (dup2(p[1], 1) == -1) {
			_pam_log(LOG_ERR, "dup2: %s", strerror(errno));
			_exit(127);
		}
		for (i = sysconf(_SC_OPEN_MAX); i >= 0; i--) {
			if (i != 1)
				close(i);
		}
		open("/dev/null", O_RDONLY);
		if (logfile) {
			if (open(logfile, O_CREAT|O_APPEND|O_WRONLY,
				 0644) == -1) {
				_pam_log(LOG_ERR, "open(%s): %s",
					 logfile, strerror(errno));
				_exit(127);
			}
		} else
			dup2(1, 2);
		
		execv(argv[0], argv);
		_exit(127);
	}

	/* master */
	close(p[1]);

	start = time(NULL);
	intr = 0;
	rc = 0;
	status = 0;
	for (i = 0; total < max_output_size;) {
		FD_ZERO(&rd);
		FD_SET(p[0], &rd);

		if (intr) {
			rc = waitpid(pid, &status, WNOHANG);
			if (rc == pid)
				break;
			if (rc == (pid_t)-1) {
				_pam_log(LOG_ERR, "waitpid: %s",
					 strerror(errno));
				break;
			}
			intr = 0;
		}
		ttl = timeout_option - (time(NULL) - start);
		if (ttl <= 0) {
			_pam_log(LOG_ERR, "timed out reading from %s",
				 argv[0]);
			break;
		}
		tv.tv_sec = ttl;
		tv.tv_usec = 0;
		rc = select(p[0] + 1, &rd, NULL, NULL, &tv);
		if (rc < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				intr = 1;
				continue;
			}
			_pam_log(LOG_ERR, "select: %s", strerror(errno));
		}
		if (i == sizeof(buf) - 1) {
			char *p;
			buf[i] = 0;
			p = strrchr(buf, '\n');
			if (p)
				*p++ = 0;
			pam_info(pamh, "%s", buf);
			if (p && *p) {
				i = strlen(p);
				memmove(buf, p, i);
			}
		}
		if (FD_ISSET(p[0], &rd)) {
			char c;
			
			rc = read(p[0], &c, 1);
			if (rc == 1) {
				buf[i++] = c;
				total++;
			} else if (rc == 0
				   || errno == EINTR || errno == EAGAIN) {
				intr = 1;
				continue;
			} else {
				_pam_log(LOG_ERR, "read: %s", strerror(errno));
				break;
			}
		}
	}
	if (i) {
		buf[i] = 0;
		pam_info(pamh, "%s", buf);
	}
	close(p[0]);

	if (rc != pid) {
		_pam_log(LOG_NOTICE, "killing %s (pid %lu)",
			 argv[0], (unsigned long) pid);
		kill(pid, SIGKILL);
		
		while ((rc = waitpid(pid, &status, 0)) == -1 &&
		       errno == EINTR);
		if (rc == (pid_t)-1) {
			_pam_log(LOG_ERR, "waitpid: %s", strerror(errno));
			return PAM_SYSTEM_ERR;
		}
	} else if (WIFEXITED(status)) {
		status = WEXITSTATUS(status);
		if (status) {
			_pam_log(LOG_ERR, "%s exited with status %d",
				 argv[0], status);
			return PAM_SYSTEM_ERR;
		}
	} else if (WIFSIGNALED(status)) {
		status = WTERMSIG(status);
		_pam_log(LOG_ERR, "%s got signal %d", argv[0], status);
		return PAM_SYSTEM_ERR;
	} else if (status) {
		_pam_log(LOG_ERR, "%s failed: unknown status 0x%x",
			 argv[0], status);
		return PAM_SYSTEM_ERR;
	}
	return PAM_SUCCESS;
}
/* authenticates user on remote TACACS+ server
 * returns PAM_SUCCESS if the supplied username and password
 * pair is valid
 */
PAM_EXTERN
int pam_sm_authenticate (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    int srv_i;
    int tac_fd, status, msg, communicating;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse(argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)",
            __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);

    /* uwzgledniac PAM_DISALLOW_NULL_AUTHTOK */

    retval = tacacs_get_password (pamh, flags, ctrl, &pass);
    if (retval != PAM_SUCCESS || pass == NULL || *pass == '\0') {
        _pam_log(LOG_ERR, "unable to obtain password");
        return PAM_CRED_INSUFFICIENT;
    }

    retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
    if (retval != PAM_SUCCESS) {
        _pam_log(LOG_ERR, "unable to set password");
        return PAM_CRED_INSUFFICIENT;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: password obtained", __FUNCTION__);

    tty = _pam_get_terminal(pamh);
    if (!strncmp(tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    status = PAM_AUTHINFO_UNAVAIL;
    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        if (ctrl & PAM_TAC_DEBUG)
            syslog(LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key);
        if (tac_fd < 0) {
            _pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i);
            continue;
        }
        if (tac_authen_send(tac_fd, user, pass, tty, r_addr) < 0) {
            close(tac_fd);
            _pam_log(LOG_ERR, "error sending auth req to TACACS+ server");
            continue;
        }
        communicating = 1;
        while (communicating) {
            msg = tac_authen_read(tac_fd);

            /* talk the protocol */
            switch (msg) {
                case TAC_PLUS_AUTHEN_STATUS_PASS:
                    /* success */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_PASS");

                    status = PAM_SUCCESS;
                    communicating = 0;
                    active_server.addr = tac_srv[srv_i].addr;
                    active_server.key = tac_srv[srv_i].key;

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i);
                    break;

                case TAC_PLUS_AUTHEN_STATUS_FAIL:
                    /* forget it */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FAIL");

                    status = PAM_AUTH_ERR;
                    communicating = 0;
                    _pam_log(LOG_ERR, "auth failed: %d", msg);
                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETDATA:
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETDATA");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETUSER:
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETUSER");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETPASS:
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETPASS");

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

                    if (tac_cont_send(tac_fd, pass) < 0) {
                        _pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
                        communicating = 0;
                        break;
                    }
                    /* continue the while loop; go read tac response */
                    break;

                case TAC_PLUS_AUTHEN_STATUS_RESTART:
                    /* try it again */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_RESTART");

                    /*
                     * not implemented
                     * WdJ: I *think* you can just do tac_authen_send(user, pass) again
                     *      but I'm not sure
                     */
                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_ERROR:
                    /* server has problems */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_ERROR");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_FOLLOW:
                    /* server tells to try a different server address */
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FOLLOW");

                    communicating = 0;
                    break;

                default:
                    if (msg < 0) {
                        /* connection error */
                        communicating = 0;
                        if (ctrl & PAM_TAC_DEBUG)
                            syslog(LOG_DEBUG, "error communicating with tacacs server");
                        break;
                    }

                    /* unknown response code */
                    communicating = 0;
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: unknown response 0x%02x", msg);
            }
        }    /* end while(communicating) */
        close(tac_fd);

        if (status == PAM_SUCCESS || status == PAM_AUTH_ERR)
            break;
    }
    if (status != PAM_SUCCESS && status != PAM_AUTH_ERR)
        _pam_log(LOG_ERR, "no more servers to connect");

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: exit with pam status: %d", __FUNCTION__, status);

    bzero(pass, strlen (pass));
    free(pass);
    pass = NULL;

    return status;
}    /* pam_sm_authenticate */
Example #15
0
static int process_args(pam_handle_t *pamh
			, int argc, const char **argv, const char *type
			, char ***evp, const char **filtername)
{
    int ctrl=0;

    while (argc-- > 0) {
	if (strcmp("debug",*argv) == 0) {
	    ctrl |= FILTER_DEBUG;
	} else if (strcmp("new_term",*argv) == 0) {
	    ctrl |= NEW_TERM;
	} else if (strcmp("non_term",*argv) == 0) {
	    ctrl |= NON_TERM;
	} else if (strcmp("run1",*argv) == 0) {
	    ctrl |= FILTER_RUN1;
	    if (argc <= 0) {
		_pam_log(LOG_ALERT,"no run filter supplied");
	    } else
		break;
	} else if (strcmp("run2",*argv) == 0) {
	    ctrl |= FILTER_RUN2;
	    if (argc <= 0) {
		_pam_log(LOG_ALERT,"no run filter supplied");
	    } else
		break;
	} else {
	    _pam_log(LOG_ERR, "unrecognized option: %s (ignored)", *argv);
	}
	++argv;                   /* step along list */
    }

    if (argc < 0) {
	/* there was no reference to a filter */
	*filtername = NULL;
	*evp = NULL;
    } else {
	char **levp;
	const char *tmp;
	int i,size;

	*filtername = *++argv;
	if (ctrl & FILTER_DEBUG) {
	    _pam_log(LOG_DEBUG,"will run filter %s\n", *filtername);
	}

	levp = (char **) malloc(5*sizeof(char *));
	if (levp == NULL) {
	    _pam_log(LOG_CRIT,"no memory for environment of filter");
	    return -1;
	}

	for (size=i=0; i<argc; ++i) {
	    size += strlen(argv[i])+1;
	}

	/* the "ARGS" variable */

#define ARGS_OFFSET    5                          /*  sizeof("ARGS=");  */
#define ARGS_NAME      "ARGS="

	size += ARGS_OFFSET;

	levp[0] = (char *) malloc(size);
	if (levp[0] == NULL) {
	    _pam_log(LOG_CRIT,"no memory for filter arguments");
	    if (levp) {
		free(levp);
	    }
	    return -1;
	}

	strncpy(levp[0],ARGS_NAME,ARGS_OFFSET);
	for (i=0,size=ARGS_OFFSET; i<argc; ++i) {
	    strcpy(levp[0]+size, argv[i]);
	    size += strlen(argv[i]);
	    levp[0][size++] = ' ';
	}
	levp[0][--size] = '\0';                    /* <NUL> terminate */

	/* the "SERVICE" variable */

#define SERVICE_OFFSET    8                    /*  sizeof("SERVICE=");  */
#define SERVICE_NAME      "SERVICE="

	pam_get_item(pamh, PAM_SERVICE, (const void **)&tmp);
	size = SERVICE_OFFSET+strlen(tmp);

	levp[1] = (char *) malloc(size+1);
	if (levp[1] == NULL) {
	    _pam_log(LOG_CRIT,"no memory for service name");
	    if (levp) {
		free(levp[0]);
		free(levp);
	    }
	    return -1;
	}

	strncpy(levp[1],SERVICE_NAME,SERVICE_OFFSET);
	strcpy(levp[1]+SERVICE_OFFSET, tmp);
	levp[1][size] = '\0';                      /* <NUL> terminate */

	/* the "USER" variable */

#define USER_OFFSET    5                          /*  sizeof("USER="******"USER="******"<unknown>";
	}
	size = USER_OFFSET+strlen(tmp);

	levp[2] = (char *) malloc(size+1);
	if (levp[2] == NULL) {
	    _pam_log(LOG_CRIT,"no memory for user's name");
	    if (levp) {
		free(levp[1]);
		free(levp[0]);
		free(levp);
	    }
	    return -1;
	}

	strncpy(levp[2],USER_NAME,USER_OFFSET);
	strcpy(levp[2]+USER_OFFSET, tmp);
	levp[2][size] = '\0';                      /* <NUL> terminate */

	/* the "USER" variable */

#define TYPE_OFFSET    5                          /*  sizeof("TYPE=");  */
#define TYPE_NAME      "TYPE="

	size = TYPE_OFFSET+strlen(type);

	levp[3] = (char *) malloc(size+1);
	if (levp[3] == NULL) {
	    _pam_log(LOG_CRIT,"no memory for type");
	    if (levp) {
		free(levp[2]);
		free(levp[1]);
		free(levp[0]);
		free(levp);
	    }
	    return -1;
	}

	strncpy(levp[3],TYPE_NAME,TYPE_OFFSET);
	strcpy(levp[3]+TYPE_OFFSET, type);
	levp[3][size] = '\0';                      /* <NUL> terminate */

	levp[4] = NULL;	                     /* end list */

	*evp = levp;
    }

    if ((ctrl & FILTER_DEBUG) && *filtername) {
	char **e;

	_pam_log(LOG_DEBUG,"filter[%s]: %s",type,*filtername);
	_pam_log(LOG_DEBUG,"environment:");
	for (e=*evp; e && *e; ++e) {
	    _pam_log(LOG_DEBUG,"  %s",*e);
	}
    }

    return ctrl;
}
Example #16
0
int _pam_account(pam_handle_t *pamh, int argc, const char **argv,
    int type, char *cmd) {

    int retval;
    static int ctrl;
    char *user = NULL;
    char *tty = NULL;
    char *r_addr = NULL;
    char *typemsg;
    int status = PAM_SESSION_ERR;
  
    typemsg = tac_acct_flag2str(type);
    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: [%s] called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, typemsg, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: tac_srv_no=%d", __FUNCTION__, tac_srv_no);
  
    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: username [%s] obtained", __FUNCTION__, user);
  
    tty = _pam_get_terminal(pamh);
    if(!strncmp(tty, "/dev/", 5)) 
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    /* checks for specific data required by TACACS+, which should
       be supplied in command line  */
    if(tac_service == NULL || *tac_service == '\0') {
        _pam_log (LOG_ERR, "TACACS+ service type not configured");
        return PAM_AUTH_ERR;
    }
    if(tac_protocol == NULL || *tac_protocol == '\0') {
        _pam_log (LOG_ERR, "TACACS+ protocol type not configured");
        return PAM_AUTH_ERR;
    }

    /* when this module is called from within pppd or other
       application dealing with serial lines, it is likely
       that we will get hit with signal caused by modem hangup;
       this is important only for STOP packets, it's relatively
       rare that modem hangs up on accounting start */
    if(type == TAC_PLUS_ACCT_FLAG_STOP) {
        signal(SIGALRM, SIG_IGN);
        signal(SIGCHLD, SIG_IGN);
        signal(SIGHUP, SIG_IGN);
    }

    if(!(ctrl & PAM_TAC_ACCT)) {
    /* normal mode, send packet to the first available server */
        int srv_i = 0;
                  
        status = PAM_SESSION_ERR;
        while ((status == PAM_SESSION_ERR) && (srv_i < tac_srv_no)) {
            int tac_fd;
                                  
            tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
            if(tac_fd < 0) {
                _pam_log(LOG_WARNING, "%s: error sending %s (fd)",
                    __FUNCTION__, typemsg);
                srv_i++;
                continue;
            }

            if (ctrl & PAM_TAC_DEBUG)
                _pam_log(LOG_DEBUG, "%s: connected with fd=%d (srv %d)", __FUNCTION__, tac_fd, srv_i);

            retval = _pam_send_account(tac_fd, type, user, tty, r_addr, cmd);
            /* return code from function in this mode is
               status of the last server we tried to send
               packet to */
            if(retval < 0) {
                _pam_log(LOG_WARNING, "%s: error sending %s (acct)",
                    __FUNCTION__, typemsg);
            } else {
                status = PAM_SUCCESS;
                if (ctrl & PAM_TAC_DEBUG) 
                    _pam_log(LOG_DEBUG, "%s: [%s] for [%s] sent",
                        __FUNCTION__, typemsg,user);
            }
            close(tac_fd);
            srv_i++;
        }
    } else {
        /* send packet to all servers specified */
        int srv_i;
                  
        status = PAM_SESSION_ERR;
        for(srv_i = 0; srv_i < tac_srv_no; srv_i++) {
            int tac_fd;
                                  
            tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
            if(tac_fd < 0) {
                _pam_log(LOG_WARNING, "%s: error sending %s (fd)",
                    __FUNCTION__, typemsg);
                continue;
            }

            if (ctrl & PAM_TAC_DEBUG)
                _pam_log(LOG_DEBUG, "%s: connected with fd=%d (srv %d)", __FUNCTION__, tac_fd, srv_i);

            retval = _pam_send_account(tac_fd, type, user, tty, r_addr, cmd);
            /* return code from function in this mode is
               status of the last server we tried to send
               packet to */
            if(retval < 0) {
                _pam_log(LOG_WARNING, "%s: error sending %s (acct)",
                    __FUNCTION__, typemsg);
            } else {
                status = PAM_SUCCESS;
                if (ctrl & PAM_TAC_DEBUG) 
                    _pam_log(LOG_DEBUG, "%s: [%s] for [%s] sent",
                        __FUNCTION__, typemsg,user);
            }
            close(tac_fd);
        }
    }  /* acct mode */

    if(type == TAC_PLUS_ACCT_FLAG_STOP) {
        signal(SIGALRM, SIG_DFL);
        signal(SIGCHLD, SIG_DFL);
        signal(SIGHUP, SIG_DFL);
    }
    return status;
}                               
Example #17
0
/* authenticates user on remote TACACS+ server
 * returns PAM_SUCCESS if the supplied username and password
 * pair is valid 
 */
PAM_EXTERN 
int pam_sm_authenticate (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    int srv_i;
    int tac_fd;
    int status = PAM_AUTH_ERR;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);
  
    /* uwzgledniac PAM_DISALLOW_NULL_AUTHTOK */

    retval = tacacs_get_password (pamh, flags, ctrl, &pass);
    if (retval != PAM_SUCCESS || pass == NULL || *pass == '\0') {
        _pam_log (LOG_ERR, "unable to obtain password");
        return PAM_CRED_INSUFFICIENT;
    }

    retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
    if (retval != PAM_SUCCESS) {
        _pam_log (LOG_ERR, "unable to set password");
        return PAM_CRED_INSUFFICIENT;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: password obtained", __FUNCTION__);

    tty = _pam_get_terminal(pamh);
    if (!strncmp (tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        int msg = TAC_PLUS_AUTHEN_STATUS_FAIL;
        if (ctrl & PAM_TAC_DEBUG)
            syslog (LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
        if (tac_fd < 0) {
            _pam_log (LOG_ERR, "connection failed srv %d: %m", srv_i);
            if (srv_i == tac_srv_no-1) {
                _pam_log (LOG_ERR, "no more servers to connect");
                return PAM_AUTHINFO_UNAVAIL;
            }
            continue;
        }

        if (tac_authen_send(tac_fd, user, pass, tty, r_addr) < 0) {
            _pam_log (LOG_ERR, "error sending auth req to TACACS+ server");
            status = PAM_AUTHINFO_UNAVAIL;
        } else {
            msg = tac_authen_read(tac_fd);
            if (msg == TAC_PLUS_AUTHEN_STATUS_GETPASS) {
                if (ctrl & PAM_TAC_DEBUG)
                    syslog (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);
                if (tac_cont_send(tac_fd, pass) < 0) {
                    _pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
                    status = PAM_AUTHINFO_UNAVAIL;
                } else {
                    msg = tac_authen_read(tac_fd);
                    if (msg != TAC_PLUS_AUTHEN_STATUS_PASS) {
                        _pam_log (LOG_ERR, "auth failed: %d", msg);
                        status = PAM_AUTH_ERR;
                    } else {
                        /* OK, we got authenticated; save the server that
                           accepted us for pam_sm_acct_mgmt and exit the loop */
                        status = PAM_SUCCESS;
                        active_server = tac_srv[srv_i];
                        active_key = tac_srv_key[srv_i];
                        close(tac_fd);
                        break;
                    }
                }
            } else if (msg != TAC_PLUS_AUTHEN_STATUS_PASS) {
                _pam_log (LOG_ERR, "auth failed: %d", msg);
                status = PAM_AUTH_ERR;
            } else {
                /* OK, we got authenticated; save the server that
                   accepted us for pam_sm_acct_mgmt and exit the loop */
                status = PAM_SUCCESS;
                active_server = tac_srv[srv_i];
                active_key = tac_srv_key[srv_i];
                close(tac_fd);
                break;
            }
        }
        close(tac_fd);
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: exit with pam status: %i", __FUNCTION__, status);

    bzero (pass, strlen (pass));
    free(pass);
    pass = NULL;

    return status;
}    /* pam_sm_authenticate */
Example #18
0
/* authorizes user on remote TACACS+ server, i.e. checks
 * his permission to access requested service
 * returns PAM_SUCCESS if the service is allowed
 */
PAM_EXTERN 
int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int retval, ctrl, status=PAM_AUTH_ERR;
    char *user;
    char *tty;
    char *r_addr;
    struct areply arep;
    struct tac_attrib *attr = NULL;
    int tac_fd;

    user = tty = r_addr = NULL;
  
    /* this also obtains service name for authorization
       this should be normally performed by pam_get_item(PAM_SERVICE)
       but since PAM service names are incompatible TACACS+
       we have to pass it via command line argument until a better
       solution is found ;) */
    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);
  
    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: username obtained [%s]", __FUNCTION__, user);
  
    tty = _pam_get_terminal(pamh);
    if(!strncmp(tty, "/dev/", 5)) 
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: tty obtained [%s]", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: rhost obtained [%s]", __FUNCTION__, r_addr);
  
    /* checks if user has been successfully authenticated
       by TACACS+; we cannot solely authorize user if it hasn't
       been authenticated or has been authenticated by method other
       than TACACS+ */
    if(!active_server) {
        _pam_log (LOG_ERR, "user not authenticated by TACACS+");
        return PAM_AUTH_ERR;
    }
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: active server is [%s]", __FUNCTION__,
            tac_ntop(active_server->ai_addr, active_server->ai_addrlen));

    /* checks for specific data required by TACACS+, which should
       be supplied in command line  */
    if(tac_service == NULL || *tac_service == '\0') {
        _pam_log (LOG_ERR, "TACACS+ service type not configured");
        return PAM_AUTH_ERR;
    }
    if(tac_protocol == NULL || *tac_protocol == '\0') {
        _pam_log (LOG_ERR, "TACACS+ protocol type not configured");
        return PAM_AUTH_ERR;
    }

    tac_add_attrib(&attr, "service", tac_service);
    tac_add_attrib(&attr, "protocol", tac_protocol);

    tac_fd = tac_connect_single(active_server, active_key);
    if(tac_fd < 0) {
        _pam_log (LOG_ERR, "TACACS+ server unavailable");
        if(arep.msg != NULL) free (arep.msg);
        close(tac_fd);
        return PAM_AUTH_ERR;
    }

    retval = tac_author_send(tac_fd, user, tty, r_addr, attr);

    tac_free_attrib(&attr);
  
    if(retval < 0) {
        _pam_log (LOG_ERR, "error getting authorization");
        if(arep.msg != NULL) free (arep.msg);
        close(tac_fd);
        return PAM_AUTH_ERR;
    }

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: sent authorization request", __FUNCTION__);
  
    tac_author_read(tac_fd, &arep);

    if(arep.status != AUTHOR_STATUS_PASS_ADD &&
        arep.status != AUTHOR_STATUS_PASS_REPL) {

        _pam_log (LOG_ERR, "TACACS+ authorisation failed for [%s]", user);
        if(arep.msg != NULL) free (arep.msg);
        close(tac_fd);
        return PAM_PERM_DENIED;
    }

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: user [%s] successfully authorized", __FUNCTION__, user);
  
    status = PAM_SUCCESS;
  
    attr = arep.attr;
    while (attr != NULL)  {
        char attribute[attr->attr_len];
        char value[attr->attr_len];
        char *sep;

        sep = index(attr->attr, '=');
        if(sep == NULL)
            sep = index(attr->attr, '*');
        if(sep != NULL) {
            bcopy(attr->attr, attribute, attr->attr_len-strlen(sep));
            attribute[attr->attr_len-strlen(sep)] = '\0';
            bcopy(sep, value, strlen(sep));
            value[strlen(sep)] = '\0';

            size_t i;
            for (i = 0; attribute[i] != '\0'; i++) {
                attribute[i] = toupper(attribute[i]);
                if (attribute[i] == '-')
                    attribute[i] = '_';
            }

            if (ctrl & PAM_TAC_DEBUG)
                _pam_log(LOG_DEBUG, "%s: returned attribute `%s%s' from server", __FUNCTION__, attribute, value);

            /* make returned attributes available for other PAM modules via PAM environment */
            if (pam_putenv(pamh, strncat(attribute, value, strlen(value))) != PAM_SUCCESS)
                _pam_log(LOG_WARNING, "%s: unable to set PAM environment", __FUNCTION__);

        } else {
            _pam_log(LOG_WARNING, "%s: invalid attribute `%s', no separator", __FUNCTION__, attr->attr);
        }
        attr = attr->next;
    }

    /* free returned attributes */
    if(arep.attr != NULL) tac_free_attrib(&arep.attr);
    if(arep.msg != NULL) free (arep.msg);
    close(tac_fd);

    return status;
}    /* pam_sm_acct_mgmt */
Example #19
0
/* expected hook for auth service */
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
				   int argc, const char **argv) {
    int retval, pcnt, pwdfilename_found;
    const char *name;
    char *password;
    char pwdfilename[PWDFN_LEN];
    char salt[12], stored_crypted_password[CRYPTED_BCPWD_LEN+1];
    char *crypted_password;
    FILE *pwdfile;
    int use_flock = 0;
    int use_delay = 1;
    int temp_result = 0;
    
    /* we require the pwdfile switch and argument to be present, else we don't work */
    /* pcnt is the parameter counter variable for iterating through argv */
    pcnt = pwdfilename_found = 0;
    do {
	/* see if the current parameter looks like "pwdfile" */
	if (strcmp(argv[pcnt],PWDF_PARAM)==0) {
	    /* if argv is long enough, grab the subsequent parameter */
	    if (pcnt+1 < argc) {
		/* make sure we can't overflow */
		strncpy(pwdfilename,argv[++pcnt],PWDFN_LEN);
		/* indicate that we've found it */
		pwdfilename_found = 1;
	    }
	    /* also check for "pwdfile=blah" */
	} else if (strncmp(argv[pcnt],PWDF_PARAM "=",sizeof(PWDF_PARAM "=")-1)==0) {
	    /* make sure we can't overflow */
	    strncpy(pwdfilename,argv[pcnt]+sizeof(PWDF_PARAM),PWDFN_LEN);
	    /* indicate that we've found it */
	    pwdfilename_found = 1;
	} else if (strcmp(argv[pcnt],FLOCK_PARAM)==0) {
	    /* we have a "flock" parameter */
	    use_flock = 1;
	} else if (strcmp(argv[pcnt],"no" FLOCK_PARAM)==0) {
	    /* or a "noflock" parameter */
	    use_flock = 0;
	} else if (strcmp(argv[pcnt],NODELAY_PARAM)==0) {
	    /* no delay on authentication failure */
	    use_delay = 0;
	}
	
    } while (++pcnt < argc);
    
#ifdef HAVE_PAM_FAIL_DELAY
    if (use_delay) {
	D(("setting delay"));
	(void) pam_fail_delay(pamh, 2000000);   /* 2 sec delay for on failure */
    }
#endif
    
    /* for some or other reason, the password file wasn't specified */
    if (!pwdfilename_found) {
	_pam_log(LOG_ERR,"password file name not specified");
	return PAM_AUTHINFO_UNAVAIL;
    }
    
    /* DEBUG */
    D(_pam_log(LOG_ERR, "password filename extracted"));
    
    /* now try to open the password file */
    if ((pwdfile=fopen(pwdfilename,"r"))==NULL) {
	_pam_log(LOG_ERR,"couldn't open password file %s",pwdfilename);
	return PAM_AUTHINFO_UNAVAIL;
    }
    
    /* set a lock on the password file */
    if (use_flock && lock_fd(fileno(pwdfile)) == -1) {
	_pam_log(LOG_ERR,"couldn't lock password file %s",pwdfilename);
	return PAM_AUTHINFO_UNAVAIL;
    }
    
    /* get user name */
    if ((retval = pam_get_user(pamh,&name,"login: "******"username not found");
	fclose(pwdfile);
	return retval;
    }
    
    
    /* DEBUG */
    D(_pam_log(LOG_ERR,"username is %s", name));
    
    /* get password - code from pam_unix_auth.c */
    pam_get_item(pamh, PAM_AUTHTOK, (void *)&password);
    if (!password) {
	retval = _set_auth_tok(pamh, flags, argc, argv);
	if (retval!=PAM_SUCCESS) {
	    fclose(pwdfile);
	    return retval;
	}
    }
    pam_get_item(pamh, PAM_AUTHTOK, (void *)&password);
    
    if ((retval = pam_get_item(pamh, PAM_AUTHTOK, (void *)&password)) != PAM_SUCCESS) {
	_pam_log(LOG_ERR, "auth token not found");
	fclose(pwdfile);
	return retval;
    }
    
    /* DEBUG */
    D(_pam_log(LOG_ERR,"got password from user", password));
    
    /* now crypt password and compare to the user entry in the password file */
    /* first make sure password is long enough -- may I do this? */
    if (strlen(password)<2 || password==NULL) {
	_pam_log(LOG_ERR,"password too short or NULL");
	fclose(pwdfile);
	return PAM_AUTH_ERR;
    }
    
    /* get the crypted password corresponding to this user */
    if (!fgetpwnam(pwdfile, name, stored_crypted_password)) {
	_pam_log(LOG_ERR,"user not found in password database");
	fclose(pwdfile);
	return PAM_AUTHINFO_UNAVAIL;
    }
    
    /* DEBUG */
    D(_pam_log(LOG_ERR,"got crypted password == '%s'", stored_crypted_password));
    
    
    temp_result = 0;
    
    /* Extract the salt and set the passwd length, depending on MD5 or DES */
    if (strncmp(stored_crypted_password, "$1$", 3) == 0) {
	D(_pam_log(LOG_ERR,"password hash type is 'md5'"));
	/* get out the salt into "salt" */
	strncpy(salt, stored_crypted_password, 11);
	salt[11] = '\0';
	stored_crypted_password[CRYPTED_MD5PWD_LEN] = '\0';
	/* try both md5 crypts */
	crypted_password = Goodcrypt_md5(password, salt);
	if (strcmp(crypted_password, stored_crypted_password) == 0)
	{
	    temp_result = 1;
	}
	else
	{
	    crypted_password = Brokencrypt_md5(password, salt);
	    if (strcmp(crypted_password, stored_crypted_password) == 0)
	    {
		temp_result = 1;
	    }
	}
    } else {
	/* get the salt out into "salt" */
	strncpy(salt, stored_crypted_password, 2);
	salt[2] = '\0';
	stored_crypted_password[CRYPTED_BCPWD_LEN] = '\0';

	if (strlen(stored_crypted_password) <= CRYPTED_DESPWD_LEN) {
	    D(_pam_log(LOG_ERR,"password hash type is 'crypt'"));
	    crypted_password = crypt(password, salt);
	} else {
	    D(_pam_log(LOG_ERR,"password hash type is 'bigcrypt'"));
	    crypted_password = bigcrypt(password, salt);
	}

	if (strcmp(crypted_password, stored_crypted_password) == 0)
	{
	    temp_result = 1;
	}
    }
    
    /* DEBUG */
    D(_pam_log(LOG_ERR,"user password crypted is '%s'", crypted_password));
    
    /* if things don't match up, complain */
    if (!temp_result) 
    {
	_pam_log(LOG_ERR,"wrong password for user %s",name);
	fclose(pwdfile);
	return PAM_AUTH_ERR;
    }
    
    /* DEBUG */
    D(_pam_log(LOG_ERR,"passwords match"));
    
    /* we've gotten here, i.e. authentication was sucessful! */
    fclose(pwdfile);
    return PAM_SUCCESS;
}
Example #20
0
static int _winbind_read_password(pam_handle_t * pamh
				  ,unsigned int ctrl
				  ,const char *comment
				  ,const char *prompt1
				  ,const char *prompt2
				  ,const char **pass)
{
	int authtok_flag;
	int retval;
	const char *item;
	char *token;

	/*
	 * make sure nothing inappropriate gets returned
	 */

	*pass = token = NULL;

	/*
	 * which authentication token are we getting?
	 */

	authtok_flag = on(WINBIND__OLD_PASSWORD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK;

	/*
	 * should we obtain the password from a PAM item ?
	 */

	if (on(WINBIND_TRY_FIRST_PASS_ARG, ctrl) || on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) {
		retval = pam_get_item(pamh, authtok_flag, (const void **) &item);
		if (retval != PAM_SUCCESS) {
			/* very strange. */
			_pam_log(LOG_ALERT, 
				 "pam_get_item returned error to unix-read-password"
			    );
			return retval;
		} else if (item != NULL) {	/* we have a password! */
			*pass = item;
			item = NULL;
			return PAM_SUCCESS;
		} else if (on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) {
			return PAM_AUTHTOK_RECOVER_ERR;		/* didn't work */
		} else if (on(WINBIND_USE_AUTHTOK_ARG, ctrl)
			   && off(WINBIND__OLD_PASSWORD, ctrl)) {
			return PAM_AUTHTOK_RECOVER_ERR;
		}
	}
	/*
	 * getting here implies we will have to get the password from the
	 * user directly.
	 */

	{
		struct pam_message msg[3], *pmsg[3];
		struct pam_response *resp;
		int i, replies;

		/* prepare to converse */

		if (comment != NULL) {
			pmsg[0] = &msg[0];
			msg[0].msg_style = PAM_TEXT_INFO;
			msg[0].msg = comment;
			i = 1;
		} else {
			i = 0;
		}

		pmsg[i] = &msg[i];
		msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
		msg[i++].msg = prompt1;
		replies = 1;

		if (prompt2 != NULL) {
			pmsg[i] = &msg[i];
			msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
			msg[i++].msg = prompt2;
			++replies;
		}
		/* so call the conversation expecting i responses */
		resp = NULL;
		retval = converse(pamh, i, pmsg, &resp);

		if (resp != NULL) {

			/* interpret the response */

			if (retval == PAM_SUCCESS) {	/* a good conversation */

				token = x_strdup(resp[i - replies].resp);
				if (token != NULL) {
					if (replies == 2) {

						/* verify that password entered correctly */
						if (!resp[i - 1].resp
						    || strcmp(token, resp[i - 1].resp)) {
							_pam_delete(token);	/* mistyped */
							retval = PAM_AUTHTOK_RECOVER_ERR;
							_make_remark(pamh								    ,PAM_ERROR_MSG, MISTYPED_PASS);
						}
					}
				} else {
					_pam_log(LOG_NOTICE
						 ,"could not recover authentication token");
				}

			}
			/*
			 * tidy up the conversation (resp_retcode) is ignored
			 * -- what is it for anyway? AGM
			 */

			_pam_drop_reply(resp, i);

		} else {
			retval = (retval == PAM_SUCCESS)
			    ? PAM_AUTHTOK_RECOVER_ERR : retval;
		}
	}

	if (retval != PAM_SUCCESS) {
		if (on(WINBIND_DEBUG_ARG, ctrl))
			_pam_log(LOG_DEBUG,
			         "unable to obtain a password");
		return retval;
	}
	/* 'token' is the entered password */

	/* we store this password as an item */
	
	retval = pam_set_item(pamh, authtok_flag, token);
	_pam_delete(token);	/* clean it up */
	if (retval != PAM_SUCCESS
	    || (retval = pam_get_item(pamh, authtok_flag
				      ,(const void **) &item))
	    != PAM_SUCCESS) {
		
		_pam_log(LOG_CRIT, "error manipulating password");
		return retval;
		
	}

	*pass = item;
	item = NULL;		/* break link to password */

	return PAM_SUCCESS;
}
Example #21
0
int readconfig(struct passwd *pwd, pam_handle_t * pamh, const char *user,
               char *path, char *targetpath, char *encfs_options,
               char *fuse_options)
{
    FILE *conffile;
    char line[BUFSIZE];
    char username[USERNAME_MAX];
    int parsed;
    const char *tmp;

    // Return 1 = error, 2 = silent error (ie already mounted)

    if ((conffile = fopen(CONFIGFILE, "r")) == NULL)
    {
        _pam_log(LOG_ERR, "Failed to open conffile %s", CONFIGFILE);
        return 0;
    }

    while (fgets(line, BUFSIZE, conffile) != NULL)
    {
        if (line[0] == '#')
            continue;
        parsed =
            sscanf(line, "%s%s%s%s%s", username, path, targetpath,
                   encfs_options, fuse_options);
        if (parsed == -1)
            continue;
        if (strcmp("drop_permissions", username) == 0)
        {
            drop_permissions = 1;
            continue;
        }
        if (strcmp("encfs_default", username) == 0)
        {
            if (parsed == 2 && !strcmp("-",path) == 0)
                strcpy(default_encfs_options, path);
            continue;
        }
        if (strcmp("fuse_default", username) == 0)
        {
            if (parsed == 2 && !strcmp("-",path) == 0)
                strcpy(default_fuse_options, path);
            continue;
        }

        if (parsed == 5)
        {
            // Parsing user:
            if (strcmp("-", encfs_options) == 0)
                strcpy(encfs_options, "");
            if (strcmp("-", fuse_options) == 0)
                strcpy(fuse_options, "");

            searchAndReplace(default_encfs_options);
            searchAndReplace(encfs_options);
            
            // Check if this is the right user / default user.
            if ((strcmp("-",username) != 0) && (strcmp(user,username) != 0)
                && (strcmp("*",username) !=0))
              continue;
            
            
            if (strcmp("-",username) == 0) {
              strcat(path, "/");
                strcat(path, user);
                // Todo check if dir exists and give better error msg.
            }
            
            // If username is '*', paths are relative to $HOME
            if (strcmp("*", username) == 0
                && strcmp("-", targetpath) != 0)
            {
                if ((tmp = getHome(pwd, pamh)))
                {
                        char home[PATH_MAX];

                        strcpy(home, tmp);
                        strcat(home, "/");
                        strcat(home, path);
                        strcpy(path, home);

                        strcpy(home, tmp);
                        strcat(home, "/");
                        strcat(home, targetpath);
                        strcpy(targetpath, home);
                }
            }
            
            if (strcmp("-", targetpath) == 0)
            {
                // We do not have targetpath, construct one.
                strcpy(targetpath, "");

                if ((tmp = getHome(pwd, pamh)))
                {
                    strcpy(targetpath, tmp);
                }
            }



            // Done, check targetpath and return.

            if (!targetpath || *targetpath == '\0')
            {
                _pam_log(LOG_ERR, "Can't get to HOME dir for user %s", user);
                fclose(conffile);
                return 0;
            }

            // Check if path exists, if we're "-" then we dont care, if not we give error.
            if (is_dir(path))
            {
                // We may fail to stat this directory (EPERM) if it's mounted because of fuse's funky permission system.
                if (!is_dir(targetpath))
                {
                    if (checkmnt(targetpath))
                    {
                        // Doublecheck if we're mounted, for some reason we can't stat the dir even when root if it's mounted.
                        // we are mounted, but we return 1 anyway so we can store targetpath
                        fclose(conffile);
                        return 1;
                    }
                    _pam_log(LOG_ERR, "TargetPath for %s does not exist (%s)",
                             user, targetpath);
                    fclose(conffile);
                    return 0;
                }
                fclose(conffile);
                return 1;
            }

            // Path does not exist, if we're a specified user give error, if not keep looking.

            if ((strcmp("-", username) != 0)
              && (strcmp("*", username) != 0))
            {
                _pam_log(LOG_ERR, "Path for %s does not exist (%s)", user,
                         path);
                fclose(conffile);
                return 0;
            }
            continue;

        }

        continue;
    }


    fclose(conffile);
    return 0;
}
Example #22
0
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
				int argc, const char **argv)
{
	unsigned int lctrl;
	int retval;
	unsigned int ctrl = _pam_parse(argc, argv);

	/* <DO NOT free() THESE> */
	const char *user;
	const char *member = NULL;
	char *pass_old, *pass_new;
	/* </DO NOT free() THESE> */

	char *Announce;
	
	int retry = 0;

	/*
	 * First get the name of a user
	 */
	retval = pam_get_user(pamh, &user, "Username: "******"username was NULL!");
			return PAM_USER_UNKNOWN;
		}
		if (retval == PAM_SUCCESS && on(WINBIND_DEBUG_ARG, ctrl))
			_pam_log(LOG_DEBUG, "username [%s] obtained",
				 user);
	} else {
		if (on(WINBIND_DEBUG_ARG, ctrl))
			_pam_log(LOG_DEBUG,
				 "password - could not identify user");
		return retval;
	}

	/*
	 * obtain and verify the current password (OLDAUTHTOK) for
	 * the user.
	 */

	if (flags & PAM_PRELIM_CHECK) {
		
		/* instruct user what is happening */
#define greeting "Changing password for "
		Announce = (char *) malloc(sizeof(greeting) + strlen(user));
		if (Announce == NULL) {
		_pam_log(LOG_CRIT, 
			 "password - out of memory");
		return PAM_BUF_ERR;
		}
		(void) strcpy(Announce, greeting);
		(void) strcpy(Announce + sizeof(greeting) - 1, user);
#undef greeting
		
		lctrl = ctrl | WINBIND__OLD_PASSWORD;
		retval = _winbind_read_password(pamh, lctrl
						,Announce
						,"(current) NT password: "******"password - (old) token not obtained");
			return retval;
		}
		/* verify that this is the password for this user */
		
		retval = winbind_auth_request(user, pass_old, member, ctrl);
		
		if (retval != PAM_ACCT_EXPIRED 
		    && retval != PAM_AUTHTOK_EXPIRED
		    && retval != PAM_NEW_AUTHTOK_REQD 
		    && retval != PAM_SUCCESS) {
			pass_old = NULL;
			return retval;
		}
		
		retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old);
		pass_old = NULL;
		if (retval != PAM_SUCCESS) {
			_pam_log(LOG_CRIT, 
				 "failed to set PAM_OLDAUTHTOK");
		}
	} else if (flags & PAM_UPDATE_AUTHTOK) {
	
		/*
		 * obtain the proposed password
		 */
		
		/*
		 * get the old token back. 
		 */
		
		retval = pam_get_item(pamh, PAM_OLDAUTHTOK
				      ,(const void **) &pass_old);
		
		if (retval != PAM_SUCCESS) {
			_pam_log(LOG_NOTICE, "user not authenticated");
			return retval;
		}
		
		lctrl = ctrl;
		
		if (on(WINBIND_USE_AUTHTOK_ARG, lctrl)) {
			lctrl |= WINBIND_USE_FIRST_PASS_ARG;
		}
		retry = 0;
		retval = PAM_AUTHTOK_ERR;
		while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) {
			/*
			 * use_authtok is to force the use of a previously entered
			 * password -- needed for pluggable password strength checking
			 */
			
			retval = _winbind_read_password(pamh, lctrl
							,NULL
							,"Enter new NT password: "******"Retype new NT password: "******"password - new password not obtained");
				}
				pass_old = NULL;/* tidy up */
				return retval;
			}

			/*
			 * At this point we know who the user is and what they
			 * propose as their new password. Verify that the new
			 * password is acceptable.
			 */
			
			if (pass_new[0] == '\0') {/* "\0" password = NULL */
				pass_new = NULL;
			}
		}
		
		/*
		 * By reaching here we have approved the passwords and must now
		 * rebuild the password database file.
		 */

		retval = winbind_chauthtok_request(user, pass_old, pass_new, ctrl);
		_pam_overwrite(pass_new);
		_pam_overwrite(pass_old);
		pass_old = pass_new = NULL;
	} else {
		retval = PAM_SERVICE_ERR;
	}
	
	return retval;
}
Example #23
0
/* stolen from pam_stress */
int tacacs_get_password (pam_handle_t * pamh, int flags
    ,int ctrl, char **password) {

    const void *pam_pass;
    char *pass = NULL;

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: called", __FUNCTION__);

    if ( (ctrl & (PAM_TAC_TRY_FIRST_PASS | PAM_TAC_USE_FIRST_PASS))
        && (pam_get_item(pamh, PAM_AUTHTOK, &pam_pass) == PAM_SUCCESS)
        && (pam_pass != NULL) ) {
         if ((pass = strdup(pam_pass)) == NULL)
              return PAM_BUF_ERR;
    } else if ((ctrl & PAM_TAC_USE_FIRST_PASS)) {
         _pam_log(LOG_WARNING, "no forwarded password");
         return PAM_PERM_DENIED;
    } else {
         struct pam_message msg;
         struct pam_response *resp = NULL;
         int retval;

         /* set up conversation call */
         msg.msg_style = PAM_PROMPT_ECHO_OFF;

         if (!tac_prompt[0]) {
             msg.msg = "Password: "******"pam_sm_authenticate: NULL authtok given");

             pass = resp->resp;    /* remember this! */
             resp->resp = NULL;

             free(resp);
             resp = NULL;
         } else {
             if (ctrl & PAM_TAC_DEBUG) {
               _pam_log (LOG_DEBUG, "pam_sm_authenticate: no error reported");
               _pam_log (LOG_DEBUG, "getting password, but NULL returned!?");
             }
             return PAM_CONV_ERR;
         }
    }

    /*
       FIXME *password can still turn out as NULL
       and it can't be free()d when it's NULL
    */
    *password = pass;       /* this *MUST* be free()'d by this module */

    if(ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: obtained password", __FUNCTION__);

    return PAM_SUCCESS;
}