]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libpam/modules/pam_stress/pam_stress.c
Initial import of virgin Linux-PAM 0.65, slightly stripped down.
[FreeBSD/FreeBSD.git] / contrib / libpam / modules / pam_stress / pam_stress.c
1 /* pam_stress module */
2
3 /* $Id: pam_stress.c,v 1.12 1997/02/15 19:06:30 morgan Exp morgan $
4  *
5  * created by Andrew Morgan <morgan@parc.power.net> 1996/3/12
6  *
7  * $Log: pam_stress.c,v $
8  * Revision 1.12  1997/02/15 19:06:30  morgan
9  * fixed email
10  *
11  * Revision 1.11  1997/02/15 17:33:24  morgan
12  * removed fixed syslog buffer
13  *
14  * Revision 1.10  1996/12/01 03:11:35  morgan
15  * using _pam_macros.h now
16  *
17  * Revision 1.9  1996/11/10 20:18:10  morgan
18  * changes for .53 compilation
19  *
20  * Revision 1.8  1996/09/05 06:31:59  morgan
21  * changed return value of wipe_up from int to void
22  *
23  * Revision 1.7  1996/06/02 08:12:28  morgan
24  * updated for new static protocol, added STRESS to various user prompts
25  * and added rootok flag for pam_sm_chauthtok to look out for
26  *
27  */
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <syslog.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <unistd.h>
35
36 /*
37  * here, we make definitions for the externally accessible functions
38  * in this file (these definitions are required for static modules
39  * but strongly encouraged generally) they are used to instruct the
40  * modules include file to define their prototypes.
41  */
42
43 #define PAM_SM_AUTH
44 #define PAM_SM_ACCOUNT
45 #define PAM_SM_SESSION
46 #define PAM_SM_PASSWORD
47
48 #include <security/pam_modules.h>
49 #include <security/_pam_macros.h>
50
51 static char *_strdup(const char *x)
52 {
53      char *new;
54      new = malloc(strlen(x)+1);
55      strcpy(new,x);
56      return new;
57 }
58
59 /* log errors */
60
61 static void _pam_log(int err, const char *format, ...)
62 {
63     va_list args;
64
65     va_start(args, format);
66     openlog("PAM-stress", LOG_CONS|LOG_PID, LOG_AUTH);
67     vsyslog(err, format, args);
68     va_end(args);
69     closelog();
70 }
71
72 /* ---------- */
73
74 /* an internal function to turn all possible test arguments into bits
75    of a ctrl number */
76
77 /* generic options */
78
79 #define PAM_ST_DEBUG         01
80 #define PAM_ST_NO_WARN       02
81 #define PAM_ST_USE_PASS1     04
82 #define PAM_ST_TRY_PASS1    010
83 #define PAM_ST_ROOTOK       020
84
85 /* simulation options */
86
87 #define PAM_ST_EXPIRED       040
88 #define PAM_ST_FAIL_1       0100
89 #define PAM_ST_FAIL_2       0200
90 #define PAM_ST_PRELIM       0400
91 #define PAM_ST_REQUIRE_PWD 01000
92
93 /* some syslogging */
94
95 static void _pam_report(int ctrl, const char *name, int flags,
96                  int argc, const char **argv)
97 {
98      if (ctrl & PAM_ST_DEBUG) {
99           _pam_log(LOG_DEBUG, "CALLED: %s", name);
100           _pam_log(LOG_DEBUG, "FLAGS : 0%o%s", flags,
101                    (flags & PAM_SILENT) ? " (silent)":"");
102           _pam_log(LOG_DEBUG, "CTRL  = 0%o",ctrl);
103           _pam_log(LOG_DEBUG, "ARGV  :");
104           while (argc--) {
105                _pam_log(LOG_DEBUG, " \"%s\"", *argv++);
106           }
107      }
108 }
109
110 static int _pam_parse(int argc, const char **argv)
111 {
112      int ctrl=0;
113
114      /* step through arguments */
115      for (ctrl=0; argc-- > 0; ++argv) {
116
117           /* generic options */
118
119           if (!strcmp(*argv,"debug"))
120                ctrl |= PAM_ST_DEBUG;
121           else if (!strcmp(*argv,"no_warn"))
122                ctrl |= PAM_ST_NO_WARN;
123           else if (!strcmp(*argv,"use_first_pass"))
124                ctrl |= PAM_ST_USE_PASS1;
125           else if (!strcmp(*argv,"try_first_pass"))
126                ctrl |= PAM_ST_TRY_PASS1;
127           else if (!strcmp(*argv,"rootok"))
128                ctrl |= PAM_ST_ROOTOK;
129
130           /* simulation options */
131
132           else if (!strcmp(*argv,"expired"))   /* signal password needs
133                                                   renewal */
134                ctrl |= PAM_ST_EXPIRED;
135           else if (!strcmp(*argv,"fail_1"))    /* instruct fn 1 to fail */
136                ctrl |= PAM_ST_FAIL_1;
137           else if (!strcmp(*argv,"fail_2"))    /* instruct fn 2 to fail */
138                ctrl |= PAM_ST_FAIL_2;
139           else if (!strcmp(*argv,"prelim"))    /* instruct pam_sm_setcred
140                                                   to fail on first call */
141                ctrl |= PAM_ST_PRELIM;
142           else if (!strcmp(*argv,"required"))  /* module is fussy about the
143                                                   user being authenticated */
144                ctrl |= PAM_ST_REQUIRE_PWD;
145
146           else {
147                _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
148           }
149      }
150
151      return ctrl;
152 }
153
154 static int converse(pam_handle_t *pamh, int nargs
155                     , struct pam_message **message
156                     , struct pam_response **response)
157 {
158      int retval;
159      struct pam_conv *conv;
160
161      if ((retval = pam_get_item(pamh,PAM_CONV,(const void **)&conv))
162          == PAM_SUCCESS) {
163           retval = conv->conv(nargs, (const struct pam_message **) message
164                               , response, conv->appdata_ptr);
165           if (retval != PAM_SUCCESS) {
166                _pam_log(LOG_ERR,"(pam_stress) converse returned %d",retval);
167                _pam_log(LOG_ERR,"that is: %s",pam_strerror(pamh, retval));
168           }
169      } else {
170           _pam_log(LOG_ERR,"(pam_stress) converse failed to get pam_conv");
171      }
172
173      return retval;
174 }
175
176 /* authentication management functions */
177
178 static int stress_get_password(pam_handle_t *pamh, int flags
179                                , int ctrl, char **password)
180 {
181      char *pass;
182
183      if ( (ctrl & (PAM_ST_TRY_PASS1|PAM_ST_USE_PASS1))
184          && (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass)
185              == PAM_SUCCESS)
186          && (pass != NULL) ) {
187           pass = _strdup(pass);
188      } else if ((ctrl & PAM_ST_USE_PASS1)) {
189           _pam_log(LOG_WARNING, "pam_stress: no forwarded password");
190           return PAM_PERM_DENIED;
191      } else {                                /* we will have to get one */
192           struct pam_message msg[1],*pmsg[1];
193           struct pam_response *resp;
194           int retval;
195
196           /* set up conversation call */
197
198           pmsg[0] = &msg[0];
199           msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
200           msg[0].msg = "STRESS Password: ";
201           resp = NULL;
202
203           if ((retval = converse(pamh,1,pmsg,&resp)) != PAM_SUCCESS) {
204                return retval;
205           }
206
207           if (resp) {
208                if ((resp[0].resp == NULL) && (ctrl & PAM_ST_DEBUG)) {
209                     _pam_log(LOG_DEBUG,
210                              "pam_sm_authenticate: NULL authtok given");
211                }
212                if ((flags & PAM_DISALLOW_NULL_AUTHTOK)
213                    && resp[0].resp == NULL) {
214                     free(resp);
215                     return PAM_AUTH_ERR;
216                }
217
218                pass = resp[0].resp;          /* remember this! */
219
220                resp[0].resp = NULL;
221           } else if (ctrl & PAM_ST_DEBUG) {
222                _pam_log(LOG_DEBUG,"pam_sm_authenticate: no error reported");
223                _pam_log(LOG_DEBUG,"getting password, but NULL returned!?");
224                return PAM_CONV_ERR;
225           }
226           free(resp);
227      }
228
229      *password = pass;             /* this *MUST* be free()'d by this module */
230
231      return PAM_SUCCESS;
232 }
233
234 /* function to clean up data items */
235
236 static void wipe_up(pam_handle_t *pamh, void *data, int error)
237 {
238      free(data);
239 }
240
241 PAM_EXTERN
242 int pam_sm_authenticate(pam_handle_t *pamh, int flags,
243                         int argc, const char **argv)
244 {
245      const char *username;
246      int retval=PAM_SUCCESS;
247      char *pass;
248      int ctrl;
249
250      D(("called."));
251
252      ctrl = _pam_parse(argc,argv);
253      _pam_report(ctrl, "pam_sm_authenticate", flags, argc, argv);
254
255      /* try to get the username */
256
257      retval = pam_get_user(pamh, &username, "username: ");
258      if ((ctrl & PAM_ST_DEBUG) && (retval == PAM_SUCCESS)) {
259           _pam_log(LOG_DEBUG, "pam_sm_authenticate: username = %s", username);
260      } else if (retval != PAM_SUCCESS) {
261           _pam_log(LOG_WARNING, "pam_sm_authenticate: failed to get username");
262           return retval;
263      }
264
265      /* now get the password */
266
267      retval = stress_get_password(pamh,flags,ctrl,&pass);
268      if (retval != PAM_SUCCESS) {
269           _pam_log(LOG_WARNING, "pam_sm_authenticate: "
270                    "failed to get a password");
271           return retval;
272      }
273
274      /* try to set password item */
275
276      retval = pam_set_item(pamh,PAM_AUTHTOK,pass);
277      if (retval != PAM_SUCCESS) {
278           _pam_log(LOG_WARNING, "pam_sm_authenticate: "
279                    "failed to store new password");
280           _pam_overwrite(pass);
281           free(pass);
282           return retval;
283      }
284
285      /* clean up local copy of password */
286
287      _pam_overwrite(pass);
288      free(pass);
289      pass = NULL;
290
291      /* if we are debugging then we print the password */
292
293      if (ctrl & PAM_ST_DEBUG) {
294           (void) pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass);
295           _pam_log(LOG_DEBUG,
296                    "pam_st_authenticate: password entered is: [%s]\n",pass);
297           pass = NULL;
298      }
299
300      /* if we signal a fail for this function then fail */
301
302      if ((ctrl & PAM_ST_FAIL_1) && retval == PAM_SUCCESS)
303           return PAM_PERM_DENIED;
304
305      return retval;
306 }
307
308 PAM_EXTERN
309 int pam_sm_setcred(pam_handle_t *pamh, int flags,
310                    int argc, const char **argv)
311 {
312      int ctrl = _pam_parse(argc,argv);
313
314      D(("called. [post parsing]"));
315
316      _pam_report(ctrl, "pam_sm_setcred", flags, argc, argv);
317
318      if (ctrl & PAM_ST_FAIL_2)
319           return PAM_CRED_ERR;
320
321      return PAM_SUCCESS;
322 }
323
324 /* account management functions */
325
326 PAM_EXTERN
327 int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
328                      int argc, const char **argv)
329 {
330      int ctrl = _pam_parse(argc,argv);
331
332      D(("called. [post parsing]"));
333
334      _pam_report(ctrl,"pam_sm_acct_mgmt", flags, argc, argv);
335
336      if (ctrl & PAM_ST_FAIL_1)
337           return PAM_PERM_DENIED;
338      else if (ctrl & PAM_ST_EXPIRED) {
339           void *text = malloc(sizeof("yes")+1);
340           strcpy(text,"yes");
341           pam_set_data(pamh,"stress_new_pwd",text,wipe_up);
342           if (ctrl & PAM_ST_DEBUG) {
343                _pam_log(LOG_DEBUG,"pam_sm_acct_mgmt: need a new password");
344           }
345           return PAM_NEW_AUTHTOK_REQD;
346      }
347
348      return PAM_SUCCESS;
349 }
350
351 PAM_EXTERN
352 int pam_sm_open_session(pam_handle_t *pamh, int flags,
353                         int argc, const char **argv)
354 {
355      char *username,*service;
356      int ctrl = _pam_parse(argc,argv);
357
358      D(("called. [post parsing]"));
359
360      _pam_report(ctrl,"pam_sm_open_session", flags, argc, argv);
361
362      if ((pam_get_item(pamh, PAM_USER, (const void **) &username)
363           != PAM_SUCCESS)
364          || (pam_get_item(pamh, PAM_SERVICE, (const void **) &service)
365              != PAM_SUCCESS)) {
366           _pam_log(LOG_WARNING,"pam_sm_open_session: for whom?");
367           return PAM_SESSION_ERR;
368      }
369
370      _pam_log(LOG_NOTICE,"pam_stress: opened [%s] session for user [%s]"
371               , service, username);
372
373      if (ctrl & PAM_ST_FAIL_1)
374           return PAM_SESSION_ERR;
375
376      return PAM_SUCCESS;
377 }
378
379 PAM_EXTERN
380 int pam_sm_close_session(pam_handle_t *pamh, int flags,
381                          int argc, const char **argv)
382 {
383      const char *username,*service;
384      int ctrl = _pam_parse(argc,argv);
385
386      D(("called. [post parsing]"));
387
388      _pam_report(ctrl,"pam_sm_close_session", flags, argc, argv);
389
390      if ((pam_get_item(pamh, PAM_USER, (const void **)&username)
391           != PAM_SUCCESS)
392          || (pam_get_item(pamh, PAM_SERVICE, (const void **)&service)
393              != PAM_SUCCESS)) {
394           _pam_log(LOG_WARNING,"pam_sm_close_session: for whom?");
395           return PAM_SESSION_ERR;
396      }
397
398      _pam_log(LOG_NOTICE,"pam_stress: closed [%s] session for user [%s]"
399               , service, username);
400
401      if (ctrl & PAM_ST_FAIL_2)
402           return PAM_SESSION_ERR;
403
404      return PAM_SUCCESS;
405 }
406
407 PAM_EXTERN
408 int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
409                      int argc, const char **argv)
410 {
411      int retval;
412      int ctrl = _pam_parse(argc,argv);
413
414      D(("called. [post parsing]"));
415
416      _pam_report(ctrl,"pam_sm_chauthtok", flags, argc, argv);
417
418      /* this function should be called twice by the Linux-PAM library */
419
420      if (flags & PAM_PRELIM_CHECK) {           /* first call */
421           if (ctrl & PAM_ST_DEBUG) {
422                _pam_log(LOG_DEBUG,"pam_sm_chauthtok: prelim check");
423           }
424           if (ctrl & PAM_ST_PRELIM)
425                return PAM_TRY_AGAIN;
426
427           return PAM_SUCCESS;
428      } else if (flags & PAM_UPDATE_AUTHTOK) {  /* second call */
429           struct pam_message msg[3],*pmsg[3];
430           struct pam_response *resp;
431           const char *text;
432           char *txt=NULL;
433           int i;
434
435           if (ctrl & PAM_ST_DEBUG) {
436                _pam_log(LOG_DEBUG,"pam_sm_chauthtok: alter password");
437           }
438
439           if (ctrl & PAM_ST_FAIL_1)
440                return PAM_AUTHTOK_LOCK_BUSY;
441
442           if ( !(ctrl && PAM_ST_EXPIRED)
443                && (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
444                && (pam_get_data(pamh,"stress_new_pwd",(const void **)&text)
445                       != PAM_SUCCESS || strcmp(text,"yes"))) {
446                return PAM_SUCCESS;          /* the token has not expired */
447           }
448
449           /* the password should be changed */
450
451           if ((ctrl & PAM_ST_REQUIRE_PWD)
452               && !(getuid() == 0 && (ctrl & PAM_ST_ROOTOK))
453                ) {                       /* first get old one? */
454                char *pass;
455
456                if (ctrl & PAM_ST_DEBUG) {
457                     _pam_log(LOG_DEBUG
458                              ,"pam_sm_chauthtok: getting old password");
459                }
460                retval = stress_get_password(pamh,flags,ctrl,&pass);
461                if (retval != PAM_SUCCESS) {
462                     _pam_log(LOG_DEBUG
463                              ,"pam_sm_chauthtok: no password obtained");
464                     return retval;
465                }
466                retval = pam_set_item(pamh, PAM_OLDAUTHTOK, pass);
467                if (retval != PAM_SUCCESS) {
468                     _pam_log(LOG_DEBUG
469                              ,"pam_sm_chauthtok: could not set OLDAUTHTOK");
470                     _pam_overwrite(pass);
471                     free(pass);
472                     return retval;
473                }
474                _pam_overwrite(pass);
475                free(pass);
476           }
477
478           /* set up for conversation */
479
480           if (!(flags & PAM_SILENT)) {
481                char *username;
482
483                if ( pam_get_item(pamh, PAM_USER, (const void **)&username)
484                     || username == NULL ) {
485                     _pam_log(LOG_ERR,"no username set");
486                     return PAM_USER_UNKNOWN;
487                }
488                pmsg[0] = &msg[0];
489                msg[0].msg_style = PAM_TEXT_INFO;
490 #define _LOCAL_STRESS_COMMENT "Changing STRESS password for "
491                txt = (char *) malloc(sizeof(_LOCAL_STRESS_COMMENT)
492                                      +strlen(username)+1);
493                strcpy(txt, _LOCAL_STRESS_COMMENT);
494 #undef _LOCAL_STRESS_COMMENT
495                strcat(txt, username);
496                msg[0].msg = txt;
497                i = 1;
498           } else {
499                i = 0;
500           }
501
502           pmsg[i] = &msg[i];
503           msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
504           msg[i++].msg = "Enter new STRESS password: ";
505           pmsg[i] = &msg[i];
506           msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
507           msg[i++].msg = "Retype new STRESS password: ";
508           resp = NULL;
509
510           retval = converse(pamh,i,pmsg,&resp);
511           if (txt) {
512                free(txt);
513                txt = NULL;               /* clean up */
514           }
515           if (retval != PAM_SUCCESS) {
516                return retval;
517           }
518
519           if (resp == NULL) {
520                _pam_log(LOG_ERR, "pam_sm_chauthtok: no response from conv");
521                return PAM_CONV_ERR;
522           }
523
524           /* store the password */
525
526           if (resp[i-2].resp && resp[i-1].resp) {
527                if (strcmp(resp[i-2].resp,resp[i-1].resp)) {
528                     /* passwords are not the same; forget and return error */
529
530                     _pam_drop_reply(resp, i);
531
532                     if (!(flags & PAM_SILENT) && !(ctrl & PAM_ST_NO_WARN)) {
533                          pmsg[0] = &msg[0];
534                          msg[0].msg_style = PAM_ERROR_MSG;
535                          msg[0].msg = "Verification mis-typed; "
536                               "password unchaged";
537                          resp = NULL;
538                          (void) converse(pamh,1,pmsg,&resp);
539                          if (resp) {
540                              _pam_drop_reply(resp, 1);
541                          }
542                     }
543                     return PAM_AUTHTOK_ERR;
544                }
545
546                if (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&text)
547                    == PAM_SUCCESS) {
548                     (void) pam_set_item(pamh,PAM_OLDAUTHTOK,text);
549                     text = NULL;
550                }
551                (void) pam_set_item(pamh,PAM_AUTHTOK,resp[0].resp);
552           } else {
553                _pam_log(LOG_DEBUG,"pam_sm_chauthtok: problem with resp");
554                retval = PAM_SYSTEM_ERR;
555           }
556
557           _pam_drop_reply(resp, i);      /* clean up the passwords */
558      } else {
559           _pam_log(LOG_ERR,"pam_sm_chauthtok: this must be a Linux-PAM error");
560           return PAM_SYSTEM_ERR;
561      }
562
563      return retval;
564 }
565
566
567 #ifdef PAM_STATIC
568
569 /* static module data */
570
571 struct pam_module _pam_stress_modstruct = {
572     "pam_stress",
573     pam_sm_authenticate,
574     pam_sm_setcred,
575     pam_sm_acct_mgmt,
576     pam_sm_open_session,
577     pam_sm_close_session,
578     pam_sm_chauthtok
579 };
580
581 #endif