1=head1 NAME
2
3Authen::PAM::FAQ - Frequently-Asked Questions about Authen::PAM.
4
5=head1 SYNOPSIS
6
7perldoc Authen::PAM::FAQ
8
9=head1 VERSION
10
11This document is currently at version I<0.05>, as of I<May 4, 2005>
12
13=head1 DESCRIPTION
14
15=head2 1. Can I authenticate a user non interactively?
16
17Yes, you can although not in a very clean way. The PAM library
18has a mechanism, in a form of a conversation function, to send and
19receive text data from the user. For details of the format of the
20conversation function consult the Authen::PAM manual.  This function
21receives a list of code/string pairs. There are two codes
22(PAM_TEXT_INFO and PAM_ERROR_MSG) for displaying the associated string
23to the user and two codes (PAM_ECHO_ON and PAM_ECHO_OFF) for getting
24input from the user. As you can see the codes are rather general and
25you can not be completely sure when you are asked for a user name and
26when for a password. However, the common practice is that PAM_ECHO_ON
27is used for a user name and PAM_ECHO_OFF is used for a password. So,
28what you can do is to write your own conversation function which
29ignores the PAM_TEXT_INFO and PAM_ERROR_MSG codes and returns the
30user name for the code PAM_ECHO_ON and the password for the code
31PAM_ECHO_OFF. If you pass the user name in the initialization function
32then usually you will not be asked for it. Here is a simple example
33how to do this:
34
35  use Authen::PAM;
36  use POSIX qw(ttyname);
37
38  $service = "login";
39  $username = "foo";
40  $password = "bar";
41  $tty_name = ttyname(fileno(STDIN));
42
43  sub my_conv_func {
44    my @res;
45    while ( @_ ) {
46        my $code = shift;
47        my $msg = shift;
48        my $ans = "";
49
50	$ans = $username if ($code == PAM_PROMPT_ECHO_ON() );
51	$ans = $password if ($code == PAM_PROMPT_ECHO_OFF() );
52
53        push @res, (PAM_SUCCESS(),$ans);
54    }
55    push @res, PAM_SUCCESS();
56    return @res;
57  }
58
59  ref($pamh = new Authen::PAM($service, $username, \&my_conv_func)) ||
60	 die "Error code $pamh during PAM init!";
61
62  $res = $pamh->pam_set_item(PAM_TTY(), $tty_name);
63  $res = $pamh->pam_authenticate;
64  print $pamh->pam_strerror($res),"\n" unless $res == PAM_SUCCESS();
65
66
67The Authen::PAM module comes with a default conversation function
68which you can find in the file F<PAM.pm>.
69
70=head2 2. Can I change a password non interactively?
71
72All the discussion of the previous question also applies here.  There
73is however one serious complication. When changing a password it is
74quite possible that the PAM library will send you at lest two
75PAM_ECHO_OFF prompts - one for the old password and one or two for the
76new one. Therefore, the first thing you should do is to see what
77sequence of prompts is produced by your service. Then the conversation
78function should include some state variable to distinguish the
79different prompts. Here is an example:
80
81
82  use Authen::PAM;
83
84  $service = "passwd";
85  $username = "foo";
86  $oldpassword = "old_pass";
87  $newpassword = "new_pass";
88
89  sub my_conv_func {
90    my @res;
91    while ( @_ ) {
92        my $code = shift;
93        my $msg = shift;
94        my $ans = "";
95
96	$ans = $username if ($code == PAM_PROMPT_ECHO_ON() );
97	if ($code == PAM_PROMPT_ECHO_OFF() ) {
98	  $ans = $oldpassword if ($state == 0);
99	  $ans = $newpassword if ($state == 1);
100	  $ans = $newpassword if ($state == 2);
101
102	  $state++;
103        }
104
105        push @res, (PAM_SUCCESS(),$ans);
106    }
107    push @res, PAM_SUCCESS();
108    return @res;
109  }
110
111  ref($pamh = new Authen::PAM($service, $username, \&my_conv_func)) ||
112	 die "Error code $pamh during PAM init!";
113
114  $state = 0;
115  $res = $pamh->pam_chauthtok;
116  print $pamh->pam_strerror($res),"\n" unless $res == PAM_SUCCESS();
117
118If you are running the script as root then most likely you will not be
119prompted for an old password. In this case you can simply return the
120new password at the ECHO_OFF prompt.
121
122The $msg variable contains the text of the input prompt which you can
123use for additional test or for debugging purposes, e.g.
124
125  if ($code == PAM_PROMPT_ECHO_OFF() ) {
126    if ($state>=1 || $msg=~/new/i) { # are we asked for a new password
127       $ans = $newpassword;
128    } else {
129       $ans = $oldpassword;
130    }
131    $state++;
132  }
133
134
135=head2 3. Why are the constants PAM_AUTHTOK and PAM_OLDAUTHTOK not avaliable?
136
137The PAM_AUTHTOK and PAM_OLDAUTHTOK items can be used to pass
138authentication tokens (passwords) from one module to another. However,
139they are avaliable only to PAM modules and not to PAM applicatinos. If
140you have a special setup in which you really need to preset the
141password from the application (e.g. using a radius server) then you
142can use the pam_set_authtok module avaliable from
143L<http://www.uni-hohenheim.de/~schaefer/linux/pam/pam_set_authtok.html>.
144
145
146=head1 SEE ALSO
147
148L<Authen::PAM>
149
150=head1 AUTHOR
151
152Nikolay Pelov <NIKIP at cpan.org>
153
154=head1 COPYRIGHT
155
156Copyright (c) 1998-2005 Nikolay Pelov. All rights reserved. This file
157is part of the Authen::PAM library. This library is free software; you
158can redistribute it and/or modify it under the same terms as Perl
159itself.
160
161=cut
162
163