Print this page
    
First stab at the full Joyent wad (still needs work!!!)
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/build/openssh/patches/0010-PAM-enhancements-for-Solaris.patch
          +++ new/build/openssh/patches/0012-PAM-enhancements-for-Solaris.patch
   1      -From f31faf48842765bb3a9a5a9c400bf4613d639e94 Mon Sep 17 00:00:00 2001
        1 +From 8aa9debff40660ed691f984b805e513f3f54334b Mon Sep 17 00:00:00 2001
   2    2  From: oracle <solaris@oracle.com>
   3    3  Date: Mon, 3 Aug 2015 14:36:19 -0700
   4      -Subject: [PATCH 10/30] PAM enhancements for Solaris
        4 +Subject: [PATCH 12/36] PAM enhancements for Solaris
   5    5  
   6    6  #
   7    7  # This patch contains a couple of PAM enhancements:
   8    8  #   1) Each SSHv2 userauth method has its own PAM service name so that PAM can
   9    9  #      be used to control what userauth methods are allowed.
  10   10  #   2) The PAMServiceName and PAMServicePrefix options.
  11   11  #
  12   12  # We have contributed back this feature to the OpenSSH upstream community.
  13   13  # For more information, see https://bugzilla.mindrot.org/show_bug.cgi?id=2246
  14   14  # In the future, if these enhancements are accepted by the upsteam in a
  15   15  # later release, we will remove this patch when we upgrade to that release.
  16   16  #
  17   17  ---
  18   18   auth-pam.c     | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  19   19   auth.h         |   3 ++
  20   20   auth2.c        |  61 ++++++++++++++++++++++++++++-
  21   21   monitor.c      |  63 ++++++++++++++++++++++++++++++
  22   22   monitor.h      |   3 ++
  23   23   monitor_wrap.c |  18 +++++++++
  24   24   servconf.c     |  56 +++++++++++++++++++++++++++
  25   25   servconf.h     |  10 +++++
  26   26   sshd.1m        |  27 +++++++++++++
  27   27   sshd.c         |   5 +++
  28   28   sshd_config.4  |  18 ++++++++-
  29   29   11 files changed, 379 insertions(+), 4 deletions(-)
  30   30  
  31   31  diff --git a/auth-pam.c b/auth-pam.c
  32   32  index b941991..7bdee5c 100644
  33   33  --- a/auth-pam.c
  34   34  +++ b/auth-pam.c
  35   35  @@ -617,6 +617,72 @@ sshpam_cleanup(void)
  36   36          sshpam_handle = NULL;
  37   37   }
  38   38   
  39   39  +#ifdef PAM_ENHANCEMENT
  40   40  +char *
  41   41  +derive_pam_service_name(Authctxt *authctxt)
  42   42  +{
  43   43  +       char *svcname = xmalloc(BUFSIZ);
  44   44  +
  45   45  +       /*
  46   46  +        * If PamServiceName is set we use that for everything, including
  47   47  +        * SSHv1
  48   48  +        */
  49   49  +       if (options.pam_service_name != NULL) {
  50   50  +               (void) strlcpy(svcname, options.pam_service_name, BUFSIZ);
  51   51  +               return (svcname);
  52   52  +       }
  53   53  +
  54   54  +       if (compat20) {
  55   55  +               char *method_name = authctxt->authmethod_name;
  56   56  +
  57   57  +               if (!method_name)
  58   58  +                       fatal("Userauth method unknown while starting PAM");
  59   59  +
  60   60  +               /*
  61   61  +                * For SSHv2 we use "sshd-<userauth name>
  62   62  +                * The "sshd" prefix can be changed via the PAMServicePrefix
  63   63  +                * sshd_config option.
  64   64  +                */
  65   65  +               if (strcmp(method_name, "none") == 0) {
  66   66  +                       snprintf(svcname, BUFSIZ, "%s-none",
  67   67  +                           options.pam_service_prefix);
  68   68  +               }
  69   69  +               if (strcmp(method_name, "password") == 0) {
  70   70  +                       snprintf(svcname, BUFSIZ, "%s-password",
  71   71  +                           options.pam_service_prefix);
  72   72  +               }
  73   73  +               if (strcmp(method_name, "keyboard-interactive") == 0) {
  74   74  +                       /* "keyboard-interactive" is too long, shorten it */
  75   75  +                       snprintf(svcname, BUFSIZ, "%s-kbdint",
  76   76  +                           options.pam_service_prefix);
  77   77  +               }
  78   78  +               if (strcmp(method_name, "publickey") == 0) {
  79   79  +                       /* "publickey" is too long, shorten it */
  80   80  +                       snprintf(svcname, BUFSIZ, "%s-pubkey",
  81   81  +                           options.pam_service_prefix);
  82   82  +               }
  83   83  +               if (strcmp(method_name, "hostbased") == 0) {
  84   84  +                       snprintf(svcname, BUFSIZ, "%s-hostbased",
  85   85  +                           options.pam_service_prefix);
  86   86  +               }
  87   87  +               if (strncmp(method_name, "gssapi-", 7) == 0) {
  88   88  +                       /*
  89   89  +                        * Although OpenSSH only supports "gssapi-with-mic"
  90   90  +                        * for now. We will still map any userauth method
  91   91  +                         * prefixed with "gssapi-" to the gssapi PAM service.
  92   92  +                        */ 
  93   93  +                       snprintf(svcname, BUFSIZ, "%s-gssapi",
  94   94  +                           options.pam_service_prefix);
  95   95  +               }
  96   96  +               return svcname;
  97   97  +       } else {
  98   98  +               /* SSHv1 doesn't get to be so cool */
  99   99  +               snprintf(svcname, BUFSIZ, "sshd-v1");
 100  100  +       }
 101  101  +       return svcname;
 102  102  +}
 103  103  +#endif /* PAM_ENHANCEMENT */
 104  104  +
 105  105   static int
 106  106   sshpam_init(Authctxt *authctxt)
 107  107   {
 108  108  @@ -624,18 +690,71 @@ sshpam_init(Authctxt *authctxt)
 109  109          const char *pam_rhost, *pam_user, *user = authctxt->user;
 110  110          const char **ptr_pam_user = &pam_user;
 111  111   
 112  112  +#ifdef PAM_ENHANCEMENT
 113  113  +       const char *pam_service;
 114  114  +        const char **ptr_pam_service = &pam_service;
 115  115  +       char *svc = NULL;
 116  116  +
 117  117  +       svc = derive_pam_service_name(authctxt);
 118  118  +        debug3("PAM service is %s", svc);
 119  119  +#endif
 120  120  +
 121  121          if (sshpam_handle != NULL) {
 122  122  +#ifdef PAM_ENHANCEMENT
 123  123  +               /* get the pam service name */
 124  124  +               sshpam_err = pam_get_item(sshpam_handle,
 125  125  +                   PAM_SERVICE, (sshpam_const void **)ptr_pam_service);
 126  126  +                if (sshpam_err != PAM_SUCCESS) 
 127  127  +                   fatal("Failed to get the PAM service name");
 128  128  +               debug3("Previous pam_service is %s", pam_service ?
 129  129  +                    pam_service : "NULL");
 130  130  +
 131  131  +               /* get the pam user name */
 132  132  +               sshpam_err = pam_get_item(sshpam_handle,
 133  133  +                   PAM_USER, (sshpam_const void **)ptr_pam_user);
 134  134  +
 135  135  +               /*
 136  136  +                * only need to re-start if either user or service is 
 137  137  +                 * different.
 138  138  +                 */
 139  139  +               if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0
 140  140  +                   && strncmp(svc, pam_service, strlen(svc)) == 0) {
 141  141  +                       free(svc);
 142  142  +                       return (0);
 143  143  +                }
 144  144  +
 145  145  +               /*
 146  146  +                * Clean up previous PAM state.  No need to clean up session 
 147  147  +                * and creds.
 148  148  +                */
 149  149  +                sshpam_authenticated = 0;
 150  150  +                sshpam_account_status = -1;
 151  151  +
 152  152  +               sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, NULL);
 153  153  +               if (sshpam_err != PAM_SUCCESS)
 154  154  +                       debug3("Cannot remove PAM conv"); /* a warning only */
 155  155  +#else /* Original */
 156  156                  /* We already have a PAM context; check if the user matches */
 157  157                  sshpam_err = pam_get_item(sshpam_handle,
 158  158                      PAM_USER, (sshpam_const void **)ptr_pam_user);
 159  159                  if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
 160  160                          return (0);
 161  161  +#endif /* PAM_ENHANCEMENT */
 162  162                  pam_end(sshpam_handle, sshpam_err);
 163  163                  sshpam_handle = NULL;
 164  164          }
 165  165          debug("PAM: initializing for \"%s\"", user);
 166  166  +
 167  167  +#ifdef PAM_ENHANCEMENT
 168  168  +        debug3("Starting PAM service %s for user %s method %s", svc, user,
 169  169  +            authctxt->authmethod_name);
 170  170  +       sshpam_err =
 171  171  +           pam_start(svc, user, &store_conv, &sshpam_handle);
 172  172  +       free(svc);
 173  173  +#else /* Original */
 174  174          sshpam_err =
 175  175              pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle);
 176  176  +#endif
 177  177          sshpam_authctxt = authctxt;
 178  178   
 179  179          if (sshpam_err != PAM_SUCCESS) {
 180  180  diff --git a/auth.h b/auth.h
 181  181  index 8b27575..a0e41a4 100644
 182  182  --- a/auth.h
 183  183  +++ b/auth.h
 184  184  @@ -81,6 +81,9 @@ struct Authctxt {
 185  185   
 186  186          struct sshkey   **prev_userkeys;
 187  187          u_int            nprev_userkeys;
 188  188  +#ifdef PAM_ENHANCEMENT
 189  189  +        char            *authmethod_name;
 190  190  +#endif 
 191  191   };
 192  192   /*
 193  193    * Every authentication method has to handle authentication requests for
 194  194  diff --git a/auth2.c b/auth2.c
 195  195  index 7177962..32ba663 100644
 196  196  --- a/auth2.c
 197  197  +++ b/auth2.c
 198  198  @@ -243,10 +243,21 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
 199  199                          PRIVSEP(audit_event(SSH_INVALID_USER));
 200  200   #endif
 201  201                  }
 202  202  +
 203  203  +
 204  204   #ifdef USE_PAM
 205  205  +#ifdef PAM_ENHANCEMENT
 206  206  +               /*
 207  207  +                * Start PAM here and once only, if each userauth does not
 208  208  +                * has its own PAM service.
 209  209  +                */
 210  210  +               if (options.use_pam && !options.pam_service_per_authmethod)
 211  211  +                       PRIVSEP(start_pam(authctxt));
 212  212  +#else
 213  213                  if (options.use_pam)
 214  214                          PRIVSEP(start_pam(authctxt));
 215  215   #endif
 216  216  +#endif
 217  217                  setproctitle("%s%s", authctxt->valid ? user : "unknown",
 218  218                      use_privsep ? " [net]" : "");
 219  219                  authctxt->service = xstrdup(service);
 220  220  @@ -277,6 +288,18 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
 221  221          /* try to authenticate user */
 222  222          m = authmethod_lookup(authctxt, method);
 223  223          if (m != NULL && authctxt->failures < options.max_authtries) {
 224  224  +
 225  225  +#if defined(USE_PAM) && defined(PAM_ENHANCEMENT)
 226  226  +               /* start PAM service for each userauth */
 227  227  +                if (options.use_pam && options.pam_service_per_authmethod) {
 228  228  +                               if (authctxt->authmethod_name != NULL)
 229  229  +                               free(authctxt->authmethod_name);
 230  230  +                        authctxt->authmethod_name = xstrdup(method);
 231  231  +                        if (use_privsep)
 232  232  +                                mm_inform_authmethod(method);
 233  233  +                       PRIVSEP(start_pam(authctxt));
 234  234  +               }
 235  235  +#endif
 236  236                  debug2("input_userauth_request: try method %s", method);
 237  237                  authenticated = m->userauth(authctxt);
 238  238          }
 239  239  @@ -295,6 +318,10 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
 240  240          char *methods;
 241  241          int partial = 0;
 242  242   
 243  243  +#ifdef  PAM_ENHANCEMENT
 244  244  +        debug3("%s: entering", __func__);
 245  245  +#endif
 246  246  +
 247  247          if (!authctxt->valid && authenticated)
 248  248                  fatal("INTERNAL ERROR: authenticated invalid user %s",
 249  249                      authctxt->user);
 250  250  @@ -311,6 +338,25 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
 251  251          }
 252  252   
 253  253          if (authenticated && options.num_auth_methods != 0) {
 254  254  +
 255  255  +#if defined(USE_PAM) && defined(PAM_ENHANCEMENT)
 256  256  +                /*
 257  257  +                 * If each userauth has its own PAM service, then PAM need to 
 258  258  +                 * perform account check for this service.
 259  259  +                 */
 260  260  +                if (options.use_pam && options.pam_service_per_authmethod &&
 261  261  +                    !PRIVSEP(do_pam_account())) {
 262  262  +                        /* if PAM returned a message, send it to the user */
 263  263  +                        if (buffer_len(&loginmsg) > 0) {
 264  264  +                                buffer_append(&loginmsg, "\0", 1);
 265  265  +                                userauth_send_banner(buffer_ptr(&loginmsg));
 266  266  +                                packet_write_wait();
 267  267  +                        }
 268  268  +
 269  269  +                        fatal("Access denied for user %s by PAM account "
 270  270  +                            "configuration", authctxt->user);
 271  271  +                }
 272  272  +#endif
 273  273                  if (!auth2_update_methods_lists(authctxt, method, submethod)) {
 274  274                          authenticated = 0;
 275  275                          partial = 1;
 276  276  @@ -324,7 +370,20 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
 277  277                  return;
 278  278   
 279  279   #ifdef USE_PAM
 280  280  +
 281  281  +#ifdef PAM_ENHANCEMENT
 282  282  +        /*
 283  283  +         * PAM needs to perform account checks after auth. However, if each
 284  284  +         * userauth has its own PAM service and options.num_auth_methods != 0,
 285  285  +         * then no need to perform account checking, because it was done 
 286  286  +         * already.
 287  287  +         */
 288  288  +        if (options.use_pam && authenticated && 
 289  289  +            !(options.num_auth_methods != 0 &&
 290  290  +            options.pam_service_per_authmethod)){
 291  291  +#else
 292  292          if (options.use_pam && authenticated) {
 293  293  +#endif
 294  294                  if (!PRIVSEP(do_pam_account())) {
 295  295                          /* if PAM returned a message, send it to the user */
 296  296                          if (buffer_len(&loginmsg) > 0) {
 297  297  @@ -615,5 +674,3 @@ auth2_update_methods_lists(Authctxt *authctxt, const char *method,
 298  298                  fatal("%s: method not in AuthenticationMethods", __func__);
 299  299          return 0;
 300  300   }
 301  301  -
 302  302  -
 303  303  diff --git a/monitor.c b/monitor.c
 304  304  index a914209..b3efbb0 100644
 305  305  --- a/monitor.c
 306  306  +++ b/monitor.c
 307  307  @@ -127,6 +127,9 @@ int mm_answer_sign(int, Buffer *);
 308  308   int mm_answer_pwnamallow(int, Buffer *);
 309  309   int mm_answer_auth2_read_banner(int, Buffer *);
 310  310   int mm_answer_authserv(int, Buffer *);
 311  311  +#ifdef PAM_ENHANCEMENT
 312  312  +int mm_answer_authmethod(int, Buffer *);
 313  313  +#endif
 314  314   int mm_answer_authpassword(int, Buffer *);
 315  315   int mm_answer_bsdauthquery(int, Buffer *);
 316  316   int mm_answer_bsdauthrespond(int, Buffer *);
 317  317  @@ -206,10 +209,17 @@ struct mon_table mon_dispatch_proto20[] = {
 318  318       {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
 319  319       {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
 320  320       {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
 321  321  +#ifdef PAM_ENHANCEMENT
 322  322  +    {MONITOR_REQ_AUTHMETHOD, MON_ISAUTH, mm_answer_authmethod},
 323  323  +#endif
 324  324       {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
 325  325       {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
 326  326   #ifdef USE_PAM
 327  327  +#ifdef PAM_ENHANCEMENT
 328  328  +    {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
 329  329  +#else
 330  330       {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
 331  331  +#endif
 332  332       {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
 333  333       {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
 334  334       {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
 335  335  @@ -371,6 +381,24 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
 336  336                          if (!compat20)
 337  337                                  fatal("AuthenticationMethods is not supported"
 338  338                                      "with SSH protocol 1");
 339  339  +
 340  340  +#if defined(USE_PAM) && defined(PAM_ENHANCEMENT)
 341  341  +                        /* 
 342  342  +                         * If each userauth has its own PAM service, then PAM
 343  343  +                         * need to perform account check for this service.
 344  344  +                         */
 345  345  +                        if (options.use_pam && authenticated &&
 346  346  +                            options.pam_service_per_authmethod) {
 347  347  +                                Buffer m;
 348  348  +
 349  349  +                                buffer_init(&m);
 350  350  +                                mm_request_receive_expect(pmonitor->m_sendfd,
 351  351  +                                    MONITOR_REQ_PAM_ACCOUNT, &m);
 352  352  +                                authenticated = 
 353  353  +                                    mm_answer_pam_account(pmonitor->m_sendfd, &m);
 354  354  +                                buffer_free(&m);
 355  355  +                         }
 356  356  +#endif
 357  357                          if (authenticated &&
 358  358                              !auth2_update_methods_lists(authctxt,
 359  359                              auth_method, auth_submethod)) {
 360  360  @@ -389,8 +417,21 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
 361  361                              !auth_root_allowed(auth_method))
 362  362                                  authenticated = 0;
 363  363   #ifdef USE_PAM
 364  364  +#ifdef PAM_ENHANCEMENT
 365  365  +                        /*
 366  366  +                         * PAM needs to perform account checks after auth.
 367  367  +                         * However, if each userauth has its own PAM service
 368  368  +                         * and options.num_auth_methods != 0, then no need to
 369  369  +                         * perform account checking, because it was done 
 370  370  +                         * already.
 371  371  +                         */
 372  372  +                        if (options.use_pam && authenticated &&
 373  373  +                            !(options.num_auth_methods != 0 &&
 374  374  +                            options.pam_service_per_authmethod)) {
 375  375  +#else
 376  376                          /* PAM needs to perform account checks after auth */
 377  377                          if (options.use_pam && authenticated) {
 378  378  +#endif
 379  379                                  Buffer m;
 380  380   
 381  381                                  buffer_init(&m);
 382  382  @@ -863,6 +904,10 @@ mm_answer_pwnamallow(int sock, Buffer *m)
 383  383                  /* Allow service/style information on the auth context */
 384  384                  monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
 385  385                  monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
 386  386  +#ifdef PAM_ENHANCEMENT
 387  387  +                /* Allow authmethod information on the auth context */
 388  388  +               monitor_permit(mon_dispatch, MONITOR_REQ_AUTHMETHOD, 1);
 389  389  +#endif
 390  390          }
 391  391   #ifdef USE_PAM
 392  392          if (options.use_pam)
 393  393  @@ -903,6 +948,24 @@ mm_answer_authserv(int sock, Buffer *m)
 394  394          return (0);
 395  395   }
 396  396   
 397  397  +#ifdef PAM_ENHANCEMENT
 398  398  +int
 399  399  +mm_answer_authmethod(int sock, Buffer *m)
 400  400  +{
 401  401  +       monitor_permit_authentications(1);
 402  402  +
 403  403  +       authctxt->authmethod_name = buffer_get_string(m, NULL);
 404  404  +       debug3("%s: authmethod_name=%s", __func__, authctxt->authmethod_name);
 405  405  +
 406  406  +       if (strlen(authctxt->authmethod_name) == 0) {
 407  407  +               free(authctxt->authmethod_name);
 408  408  +               authctxt->authmethod_name = NULL;
 409  409  +       }
 410  410  +
 411  411  +       return (0);
 412  412  +}
 413  413  +#endif
 414  414  +
 415  415   int
 416  416   mm_answer_authpassword(int sock, Buffer *m)
 417  417   {
 418  418  diff --git a/monitor.h b/monitor.h
 419  419  index 93b8b66..da63e7d 100644
 420  420  --- a/monitor.h
 421  421  +++ b/monitor.h
 422  422  @@ -65,6 +65,9 @@ enum monitor_reqtype {
 423  423          MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
 424  424          MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
 425  425   
 426  426  +#ifdef PAM_ENHANCEMENT
 427  427  +        MONITOR_REQ_AUTHMETHOD = 114,
 428  428  +#endif        
 429  429   };
 430  430   
 431  431   struct mm_master;
 432  432  diff --git a/monitor_wrap.c b/monitor_wrap.c
 433  433  index eac421b..95231a3 100644
 434  434  --- a/monitor_wrap.c
 435  435  +++ b/monitor_wrap.c
 436  436  @@ -345,6 +345,24 @@ mm_inform_authserv(char *service, char *style)
 437  437          buffer_free(&m);
 438  438   }
 439  439   
 440  440  +#ifdef PAM_ENHANCEMENT
 441  441  +/* Inform the privileged process about the authentication method */
 442  442  +void
 443  443  +mm_inform_authmethod(char *authmethod)
 444  444  +{
 445  445  +       Buffer m;
 446  446  +
 447  447  +       debug3("%s entering", __func__);
 448  448  +
 449  449  +       buffer_init(&m);
 450  450  +       buffer_put_cstring(&m, authmethod);
 451  451  +
 452  452  +       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHMETHOD, &m);
 453  453  +
 454  454  +       buffer_free(&m);
 455  455  +}
 456  456  +#endif
 457  457  +
 458  458   /* Do the password authentication */
 459  459   int
 460  460   mm_auth_password(Authctxt *authctxt, char *password)
 461  461  diff --git a/servconf.c b/servconf.c
 462  462  index ad884ec..d0ca777 100644
 463  463  --- a/servconf.c
 464  464  +++ b/servconf.c
 465  465  @@ -169,6 +169,18 @@ initialize_server_options(ServerOptions *options)
 466  466          options->ip_qos_bulk = -1;
 467  467          options->version_addendum = NULL;
 468  468          options->fingerprint_hash = -1;
 469  469  +#ifdef PAM_ENHANCEMENT
 470  470  +       options->pam_service_name = NULL;
 471  471  +       options->pam_service_prefix = NULL;
 472  472  +
 473  473  +       /* 
 474  474  +        * Each user method will have its own PAM service by default.
 475  475  +        * However, if PAMServiceName is specified or the protocal version
 476  476  +        * is not compat20, then there will be only one PAM service for the
 477  477  +        * entire user authentication.
 478  478  +        */
 479  479  +       options->pam_service_per_authmethod = 1;
 480  480  +#endif
 481  481   }
 482  482   
 483  483   /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
 484  484  @@ -340,6 +352,12 @@ fill_default_server_options(ServerOptions *options)
 485  485                  options->ip_qos_bulk = IPTOS_THROUGHPUT;
 486  486          if (options->version_addendum == NULL)
 487  487                  options->version_addendum = xstrdup("");
 488  488  +
 489  489  +#ifdef PAM_ENHANCEMENT
 490  490  +       if (options->pam_service_prefix == NULL)
 491  491  +               options->pam_service_prefix = _SSH_PAM_SERVICE_PREFIX;
 492  492  +#endif
 493  493  +
 494  494          if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
 495  495                  options->fwd_opts.streamlocal_bind_mask = 0177;
 496  496          if (options->fwd_opts.streamlocal_bind_unlink == -1)
 497  497  @@ -421,6 +439,9 @@ typedef enum {
 498  498          sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
 499  499          sUsePrivilegeSeparation, sAllowAgentForwarding,
 500  500          sHostCertificate,
 501  501  +#ifdef PAM_ENHANCEMENT
 502  502  +       sPAMServicePrefix, sPAMServiceName,
 503  503  +#endif
 504  504          sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
 505  505          sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
 506  506          sKexAlgorithms, sIPQoS, sVersionAddendum,
 507  507  @@ -559,6 +580,10 @@ static struct {
 508  508          { "forcecommand", sForceCommand, SSHCFG_ALL },
 509  509          { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
 510  510          { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
 511  511  +#ifdef PAM_ENHANCEMENT
 512  512  +       { "pamserviceprefix", sPAMServicePrefix, SSHCFG_GLOBAL },
 513  513  +       { "pamservicename", sPAMServiceName, SSHCFG_GLOBAL },
 514  514  +#endif
 515  515          { "revokedkeys", sRevokedKeys, SSHCFG_ALL },
 516  516          { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
 517  517          { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
 518  518  @@ -1865,6 +1890,37 @@ process_server_config_line(ServerOptions *options, char *line,
 519  519                          options->fingerprint_hash = value;
 520  520                  break;
 521  521   
 522  522  +       case sPAMServicePrefix:
 523  523  +               arg = strdelim(&cp);
 524  524  +               if (!arg || *arg == '\0')
 525  525  +                       fatal("%s line %d: Missing argument.",
 526  526  +                           filename, linenum);
 527  527  +               if (options->pam_service_name != NULL)
 528  528  +                       fatal("%s line %d: PAMServiceName and PAMServicePrefix"
 529  529  +                           " are mutually exclusive.", filename, linenum);
 530  530  +               if (options->pam_service_prefix == NULL)
 531  531  +                       options->pam_service_prefix = xstrdup(arg);
 532  532  +               break;
 533  533  +
 534  534  +       case sPAMServiceName:
 535  535  +               arg = strdelim(&cp);
 536  536  +               if (!arg || *arg == '\0')
 537  537  +                       fatal("%s line %d: Missing argument.",
 538  538  +                           filename, linenum);
 539  539  +               if (options->pam_service_prefix != NULL)
 540  540  +                       fatal("%s line %d: PAMServiceName and PAMServicePrefix"
 541  541  +                           " are mutually exclusive.", filename, linenum);
 542  542  +               if (options->pam_service_name == NULL) {
 543  543  +                       options->pam_service_name = xstrdup(arg);
 544  544  +
 545  545  +                       /*
 546  546  +                        * When this option is specified, we will not have
 547  547  +                        * PAM service for each auth method.
 548  548  +                         */
 549  549  +                       options->pam_service_per_authmethod = 0;
 550  550  +               }
 551  551  +               break;
 552  552  +
 553  553          case sDeprecated:
 554  554                  logit("%s line %d: Deprecated option %s",
 555  555                      filename, linenum, arg);
 556  556  diff --git a/servconf.h b/servconf.h
 557  557  index f4137af..8c86b57 100644
 558  558  --- a/servconf.h
 559  559  +++ b/servconf.h
 560  560  @@ -54,6 +54,10 @@
 561  561   /* Magic name for internal sftp-server */
 562  562   #define INTERNAL_SFTP_NAME     "internal-sftp"
 563  563   
 564  564  +#ifdef PAM_ENHANCEMENT
 565  565  +#define _SSH_PAM_SERVICE_PREFIX "sshd"
 566  566  +#endif
 567  567  +
 568  568   typedef struct {
 569  569          u_int   num_ports;
 570  570          u_int   ports_from_cmdline;
 571  571  @@ -194,6 +198,12 @@ typedef struct {
 572  572          u_int   num_auth_methods;
 573  573          char   *auth_methods[MAX_AUTH_METHODS];
 574  574   
  
    | 
      ↓ open down ↓ | 
    560 lines elided | 
    
      ↑ open up ↑ | 
  
 575  575  +#ifdef PAM_ENHANCEMENT
 576  576  +       char   *pam_service_prefix;
 577  577  +       char   *pam_service_name;
 578  578  +       int     pam_service_per_authmethod;
 579  579  +#endif
 580  580  +        
 581  581          int     fingerprint_hash;
 582  582   }       ServerOptions;
 583  583   
 584  584  diff --git a/sshd.1m b/sshd.1m
 585      -index 967a753..d67efd7 100644
      585 +index ada4f25..3753f90 100644
 586  586  --- a/sshd.1m
 587  587  +++ b/sshd.1m
 588  588  @@ -944,6 +944,33 @@ concurrently for different ports, this contains the process ID of the one
 589  589   started last).
 590  590   The content of this file is not sensitive; it can be world-readable.
 591  591   .El
 592  592  +
 593  593  +.Sh SECURITY
 594  594  +sshd uses pam(3PAM) for password and keyboard-interactive methods as well as 
 595  595  +for account management, session management, and the password management for all
 596  596  +authentication methods.
 597  597  +.Pp
 598  598  +Each SSHv2 userauth type has its own PAM service name:
 599  599  +
 600  600  +.Bd -literal -offset 3n
 601  601  +
 602  602  +-----------------------------------------------
 603  603  +| SSHv2 Userauth       | PAM Service Name     |
 604  604  +-----------------------------------------------
 605  605  +| none                 | sshd-none            |
 606  606  +-----------------------------------------------
 607  607  +| password             | sshd-password        |
 608  608  +-----------------------------------------------
 609  609  +| keyboard-interactive | sshd-kbdint          |
 610  610  +-----------------------------------------------
 611  611  +| pubkey               | sshd-pubkey          |
 612  612  +-----------------------------------------------
  
    | 
      ↓ open down ↓ | 
    17 lines elided | 
    
      ↑ open up ↑ | 
  
 613  613  +| hostbased            | sshd-hostbased       |
 614  614  +-----------------------------------------------
 615  615  +| gssapi-with-mic      | sshd-gssapi          |
 616  616  +-----------------------------------------------
 617  617  +.Ed
 618  618  +
 619  619   .Sh SEE ALSO
 620  620   .Xr scp 1 ,
 621  621   .Xr sftp 1 ,
 622  622  diff --git a/sshd.c b/sshd.c
 623      -index 3df50f8..5a00ae2 100644
      623 +index 84e1dee..7e519d4 100644
 624  624  --- a/sshd.c
 625  625  +++ b/sshd.c
 626      -@@ -2159,6 +2159,11 @@ main(int ac, char **av)
      626 +@@ -2165,6 +2165,11 @@ main(int ac, char **av)
 627  627   
 628  628          sshd_exchange_identification(sock_in, sock_out);
 629  629   
 630  630  +#ifdef PAM_ENHANCEMENT
 631  631  +       if (!compat20)
 632  632  +               options.pam_service_per_authmethod = 0;
 633  633  +#endif
 634  634  +
 635  635          /* In inetd mode, generate ephemeral key only for proto 1 connections */
 636  636          if (!compat20 && inetd_flag && sensitive_data.server_key == NULL)
 637  637                  generate_ephemeral_server_key();
 638  638  diff --git a/sshd_config.4 b/sshd_config.4
 639  639  index ba4d79a..263175b 100644
 640  640  --- a/sshd_config.4
 641  641  +++ b/sshd_config.4
 642  642  @@ -1160,6 +1160,21 @@ The probability increases linearly and all connection attempts
 643  643   are refused if the number of unauthenticated connections reaches
 644  644   .Dq full
 645  645   (60).
 646  646  +.It Cm PAMServiceName
 647  647  +Specifies the PAM service name for the PAM session. The PAMServiceName and 
 648  648  +PAMServicePrefix options are mutually exclusive and if both set, sshd does not
 649  649  +start. If this option is set the service name is the same for all user 
 650  650  +authentication methods. The option has no default value. See PAMServicePrefix 
 651  651  +for more information.
 652  652  +.It Cm PAMServicePrefix
 653  653  +Specifies the PAM service name prefix for service names used for individual 
 654  654  +user authentication methods. The default is sshd. The PAMServiceName and 
 655  655  +PAMServicePrefix options are mutually exclusive and if both set, sshd does not 
 656  656  +start.
 657  657  +.Pp
 658  658  +For example, if this option is set to admincli, the service name for the 
 659  659  +keyboard-interactive authentication method is admincli-kbdint instead of the 
 660  660  +default sshd-kbdint.
 661  661   .It Cm PasswordAuthentication
 662  662   Specifies whether password authentication is allowed.
 663  663   The default is
 664  664  @@ -1573,8 +1588,7 @@ If
  
    | 
      ↓ open down ↓ | 
    28 lines elided | 
    
      ↑ open up ↑ | 
  
 665  665   is enabled, you will not be able to run
 666  666   .Xr sshd 1M
 667  667   as a non-root user.
 668  668  -The default is
 669  669  -.Dq no .
 670  670  +On Solaris, the option is always enabled.
 671  671   .It Cm UsePrivilegeSeparation
 672  672   Specifies whether
 673  673   .Xr sshd 1M
 674  674  -- 
 675      -2.3.2 (Apple Git-55)
      675 +2.5.4 (Apple Git-61)
 676  676  
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX