]> granicus.if.org Git - linux-pam/blob - libpam/pam_item.c
Relevant BUGIDs: 565470
[linux-pam] / libpam / pam_item.c
1 /* pam_item.c */
2
3 /*
4  * $Id$
5  */
6
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <syslog.h>
11
12 #include "pam_private.h"
13
14 #define RESET(X, Y)                    \
15 {                                      \
16     char *_TMP_ = (X);                 \
17     if (_TMP_ != (Y)) {                \
18          (X) = (Y) ? _pam_strdup(Y) : NULL; \
19          if (_TMP_)                    \
20               free(_TMP_);             \
21     }                                  \
22 }
23
24 /* handy version id */
25
26 unsigned int __libpam_version = LIBPAM_VERSION;
27
28 /* functions */
29
30 int pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
31 {
32     int retval;
33
34     D(("called"));
35
36     IF_NO_PAMH("pam_set_item", pamh, PAM_SYSTEM_ERR);
37     
38     retval = PAM_SUCCESS;
39
40     switch (item_type) {
41
42     case PAM_SERVICE:
43         /* Setting handlers_loaded to 0 will cause the handlers
44          * to be reloaded on the next call to a service module.
45          */
46         pamh->handlers.handlers_loaded = 0;
47         RESET(pamh->service_name, item);
48         {
49             char *tmp;
50             for (tmp=pamh->service_name; *tmp; ++tmp)
51                 *tmp = tolower(*tmp);                 /* require lower case */
52         }
53         break;
54
55     case PAM_USER:
56         RESET(pamh->user, item);
57         break;
58
59     case PAM_USER_PROMPT:
60         RESET(pamh->prompt, item);
61         break;
62
63     case PAM_TTY:
64         D(("setting tty to %s", item));
65         RESET(pamh->tty, item);
66         break;
67
68     case PAM_RUSER:
69         RESET(pamh->ruser, item);
70         break;
71
72     case PAM_RHOST:
73         RESET(pamh->rhost, item);
74         break;
75
76     case PAM_AUTHTOK:
77         /*
78          * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
79          * modules.
80          */
81         if (__PAM_FROM_MODULE(pamh)) {
82             char *_TMP_ = pamh->authtok;
83             if (_TMP_ == item)            /* not changed so leave alone */
84                 break;
85             pamh->authtok = (item) ? _pam_strdup(item) : NULL;
86             if (_TMP_) {
87                 _pam_overwrite(_TMP_);
88                 free(_TMP_);
89             }
90         } else {
91             retval = PAM_BAD_ITEM;
92         }
93
94         break;
95
96     case PAM_OLDAUTHTOK:
97         /*
98          * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
99          * modules.
100          */
101         if (__PAM_FROM_MODULE(pamh)) {
102             char *_TMP_ = pamh->oldauthtok;
103             if (_TMP_ == item)            /* not changed so leave alone */
104                 break;
105             pamh->oldauthtok = (item) ? _pam_strdup(item) : NULL;
106             if (_TMP_) {
107                 _pam_overwrite(_TMP_);
108                 free(_TMP_);
109             }
110         } else {
111             retval = PAM_BAD_ITEM;
112         }
113
114         break;
115
116     case PAM_CONV:              /* want to change the conversation function */
117         if (item == NULL) {
118             _pam_system_log(LOG_ERR,
119                             "pam_set_item: attempt to set conv() to NULL");
120             retval = PAM_PERM_DENIED;
121         } else {
122             struct pam_conv *tconv;
123             
124             if ((tconv=
125                  (struct pam_conv *) malloc(sizeof(struct pam_conv))
126                 ) == NULL) {
127                 _pam_system_log(LOG_CRIT,
128                                 "pam_set_item: malloc failed for pam_conv");
129                 retval = PAM_BUF_ERR;
130             } else {
131                 memcpy(tconv, item, sizeof(struct pam_conv));
132                 _pam_drop(pamh->pam_conversation);
133                 pamh->pam_conversation = tconv;
134             }
135         }
136         break;
137
138     case PAM_FAIL_DELAY:
139         pamh->fail_delay.delay_fn_ptr = item;
140         break;
141
142     default:
143         retval = PAM_BAD_ITEM;
144     }
145
146     return retval;
147 }
148
149 int pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
150 {
151     int retval = PAM_SUCCESS;
152
153     D(("called."));
154     IF_NO_PAMH("pam_get_item", pamh, PAM_SYSTEM_ERR);
155
156     if (item == NULL) {
157         _pam_system_log(LOG_ERR,
158                         "pam_get_item: nowhere to place requested item");
159         return PAM_PERM_DENIED;
160     }
161
162     switch (item_type) {
163     case PAM_SERVICE:
164         *item = pamh->service_name;
165         break;
166
167     case PAM_USER:
168         D(("returning user=%s", pamh->user));
169         *item = pamh->user;
170         break;
171
172     case PAM_USER_PROMPT:
173         D(("returning userprompt=%s", pamh->user));
174         *item = pamh->prompt;
175         break;
176
177     case PAM_TTY:
178         D(("returning tty=%s", pamh->tty));
179         *item = pamh->tty;
180         break;
181
182     case PAM_RUSER:
183         *item = pamh->ruser;
184         break;
185
186     case PAM_RHOST:
187         *item = pamh->rhost;
188         break;
189
190     case PAM_AUTHTOK:
191         /*
192          * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
193          * modules.
194          */
195         if (__PAM_FROM_MODULE(pamh)) {
196             *item = pamh->authtok;
197         } else {
198             retval = PAM_BAD_ITEM;
199         }
200         break;
201
202     case PAM_OLDAUTHTOK:
203         /*
204          * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
205          * modules.
206          */
207         if (__PAM_FROM_MODULE(pamh)) {
208             *item = pamh->oldauthtok;
209         } else {
210             retval = PAM_BAD_ITEM;
211         }
212         break;
213
214     case PAM_CONV:
215         *item = pamh->pam_conversation;
216         break;
217
218     case PAM_FAIL_DELAY:
219         *item = pamh->fail_delay.delay_fn_ptr;
220         break;
221
222     default:
223         retval = PAM_BAD_ITEM;
224     }
225   
226     return retval;
227 }
228
229 /*
230  * This function is the 'preferred method to obtain the username'.
231  */
232
233 int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
234 {
235     const char *use_prompt;
236     int retval;
237     struct pam_message msg,*pmsg;
238     struct pam_response *resp;
239
240     D(("called."));
241     IF_NO_PAMH("pam_get_user", pamh, PAM_SYSTEM_ERR);
242
243     if (pamh->pam_conversation == NULL) {
244         _pam_system_log(LOG_ERR, "pam_get_user: no conv element in pamh");
245         return PAM_SERVICE_ERR;
246     }
247
248     if (user == NULL) {  /* ensure the the module has suplied a destination */
249         _pam_system_log(LOG_ERR, "pam_get_user: nowhere to record username");
250         return PAM_PERM_DENIED;
251     } else
252         *user = NULL;
253     
254     if (pamh->user) {    /* have one so return it */
255         *user = pamh->user;
256         return PAM_SUCCESS;
257     }
258
259     /* will need a prompt */
260     use_prompt = prompt;
261     if (use_prompt == NULL) {
262         use_prompt = pamh->prompt;
263         if (use_prompt == NULL) {
264             use_prompt = PAM_DEFAULT_PROMPT;
265         }
266     }
267
268     /* If we are resuming an old conversation, we verify that the prompt
269        is the same.  Anything else is an error. */
270     if (pamh->former.want_user) {
271         /* must have a prompt to resume with */
272         if (! pamh->former.prompt) {
273                     _pam_system_log(LOG_ERR,
274                                    "pam_get_user: failed to resume with prompt"
275                         );
276             return PAM_ABORT;
277         }
278
279         /* must be the same prompt as last time */
280         if (strcmp(pamh->former.prompt, use_prompt)) {
281             _pam_system_log(LOG_ERR,
282                             "pam_get_user: resumed with different prompt");
283             return PAM_ABORT;
284         }
285
286         /* ok, we can resume where we left off last time */
287         pamh->former.want_user = PAM_FALSE;
288         _pam_overwrite(pamh->former.prompt);
289         _pam_drop(pamh->former.prompt);
290     }
291
292     /* converse with application -- prompt user for a username */
293     pmsg = &msg;
294     msg.msg_style = PAM_PROMPT_ECHO_ON;
295     msg.msg = use_prompt;
296     resp = NULL;
297
298     retval = pamh->pam_conversation->
299         conv(1, (const struct pam_message **) &pmsg, &resp,
300              pamh->pam_conversation->appdata_ptr);
301
302     if (retval == PAM_CONV_AGAIN) {
303         /* conversation function is waiting for an event - save state */
304         D(("conversation function is not ready yet"));
305         pamh->former.want_user = PAM_TRUE;
306         pamh->former.prompt = _pam_strdup(use_prompt);
307     } else if (resp == NULL) {
308         /*
309          * conversation should have given a response
310          */
311         D(("pam_get_user: no response provided"));
312         retval = PAM_CONV_ERR;
313     } else if (retval == PAM_SUCCESS) {            /* copy the username */
314         /*
315          * now we set the PAM_USER item -- this was missing from pre.53
316          * releases. However, reading the Sun manual, it is part of
317          * the standard API.
318          */
319         RESET(pamh->user, resp->resp);
320         *user = pamh->user;
321     }
322
323     if (resp) {
324         /*
325          * note 'resp' is allocated by the application and is
326          * correctly free()'d here
327          */
328         _pam_drop_reply(resp, 1);
329     }
330
331     D(("completed"));
332     return retval;        /* pass on any error from conversation */
333 }