~sergei.glushchenko/percona-pam-for-mysql/pam-supp-grp-test

« back to all changes in this revision

Viewing changes to src/auth_pam.c

  • Committer: Sergei Glushchenko
  • Date: 2012-02-01 15:15:19 UTC
  • mfrom: (17.2.1 percona-pam-for-mysql)
  • Revision ID: sergei.glushchenko@percona.com-20120201151519-vk3j8za6vmy479yc
MergeĀ lp:~sergei.glushchenko/percona-pam-for-mysql/use-dialog

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
 
38
38
 To install this plugin, copy the .so file to the plugin directory and do
39
39
 
40
 
 INSTALL PLUGIN auth_pam_server SONAME 'auth_pam.so';
 
40
 INSTALL PLUGIN auth_pam SONAME 'auth_pam.so';
41
41
 
42
42
 To use this plugin for one particular user, specify it at user's creation time
43
43
 (TODO: tested with localhost only):
44
44
 
45
 
 CREATE USER 'username'@'hostname' IDENTIFIED WITH auth_pam_server;
 
45
 CREATE USER 'username'@'hostname' IDENTIFIED WITH auth_pam;
46
46
 
47
47
 Alternatively UPDATE the mysql.user table to set the plugin value for an
48
48
 existing user.
114
114
  }
115
115
}
116
116
 
 
117
/** The maximum length of buffered PAM messages, i.e. any messages up to the
 
118
    next PAM reply-requiring message. 10K should be more than enough by order
 
119
    of magnitude. */
 
120
enum { max_pam_buffered_msg_len = 10240 };
 
121
 
 
122
struct pam_conv_data {
 
123
    MYSQL_PLUGIN_VIO *vio;
 
124
    MYSQL_SERVER_AUTH_INFO *info;
 
125
    unsigned char buf[max_pam_buffered_msg_len];
 
126
    unsigned char* ptr;
 
127
};
 
128
 
117
129
static void free_pam_response (struct pam_response ** resp, int n)
118
130
{
119
131
  int i;
129
141
                            struct pam_response ** resp, void *appdata_ptr)
130
142
{
131
143
  int i;
132
 
  int pkt_len;
133
 
  MYSQL_PLUGIN_VIO *vio= NULL;
 
144
  struct pam_conv_data *data= (struct pam_conv_data *)appdata_ptr;
134
145
 
135
 
  if (appdata_ptr == NULL)
 
146
  if (data == NULL)
136
147
  {
137
148
    MY_ASSERT_UNREACHABLE();
138
149
    return PAM_CONV_ERR;
139
150
  }
140
 
  vio= (MYSQL_PLUGIN_VIO *)appdata_ptr;
141
151
 
142
152
  *resp = calloc (sizeof (struct pam_response), num_msg);
143
153
  if (*resp == NULL)
145
155
 
146
156
  for (i = 0; i < num_msg; i++)
147
157
  {
148
 
    char *buf;
149
 
 
150
158
    if (!valid_pam_msg_style(msg[i]->msg_style))
151
159
    {
152
160
      free_pam_response(resp, i);
153
161
      return PAM_CONV_ERR;
154
162
    }
155
163
 
156
 
    /* Format the message.  The first byte is the message type, followed by the
157
 
    NUL-terminated message string itself.  */
158
 
    buf= malloc(strlen(msg[i]->msg) + 2);
159
 
    if (!buf)
160
 
    {
161
 
      free_pam_response(resp, i);
162
 
      return PAM_BUF_ERR;
163
 
    }
164
 
    buf[0]= pam_msg_style_to_char(msg[i]->msg_style);
165
 
    strcpy(buf + 1, msg[i]->msg);
166
 
 
167
 
    /* Write the message.  */
168
 
    if (vio->write_packet(vio, (unsigned char *)buf, strlen(buf) + 1))
169
 
    {
170
 
      free(buf);
171
 
      free_pam_response(resp, i);
172
 
      return PAM_CONV_ERR;
173
 
    }
174
 
    free(buf);
175
 
 
176
 
    /* Is the answer expected? */
177
 
    if ((msg[i]->msg_style != PAM_PROMPT_ECHO_ON)
178
 
        && (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF))
179
 
      continue;
180
 
 
181
 
    /* Read the answer */
182
 
    if ((pkt_len= vio->read_packet(vio, (unsigned char **)&buf)) < 0)
183
 
    {
184
 
      free_pam_response(resp, i);
185
 
      return PAM_CONV_ERR;
186
 
    }
187
 
 
188
 
    (*resp)[i].resp= malloc(pkt_len + 1);
189
 
    if ((*resp)[i].resp == NULL)
190
 
    {
191
 
      free_pam_response(resp, i);
192
 
      return PAM_BUF_ERR;
193
 
    }
194
 
    strncpy((*resp)[i].resp, buf, pkt_len);
195
 
    (*resp)[i].resp[pkt_len]= '\0';
 
164
    /* Append the PAM message or prompt to the unsent message buffer */
 
165
    if (msg[i]->msg)
 
166
    {
 
167
      unsigned char *last_buf_pos = data->buf + max_pam_buffered_msg_len - 1;
 
168
      if (data->ptr + strlen(msg[i]->msg) >= last_buf_pos)
 
169
      {
 
170
        free_pam_response(resp, i);
 
171
        /* Cannot happen: the PAM message buffer too small. */
 
172
        MY_ASSERT_UNREACHABLE();
 
173
        return PAM_CONV_ERR;
 
174
      }
 
175
      memcpy(data->ptr, msg[i]->msg, strlen(msg[i]->msg));
 
176
      data->ptr+= strlen(msg[i]->msg);
 
177
      *(data->ptr)++= '\n';
 
178
    }
 
179
 
 
180
    if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF
 
181
        || msg[i]->msg_style == PAM_PROMPT_ECHO_ON)
 
182
    {
 
183
      int pkt_len;
 
184
      unsigned char *pkt;
 
185
 
 
186
      /* Magic byte for the dialog plugin, '\2' is defined as ORDINARY_QUESTION
 
187
         and '\4' as PASSWORD_QUESTION there. */
 
188
      data->buf[0]= (msg[i]->msg_style == PAM_PROMPT_ECHO_ON ? '\2' : '\4');
 
189
 
 
190
      /* Write the message.  */
 
191
      if (data->vio->write_packet(data->vio, data->buf,
 
192
                                  data->ptr - data->buf - 1))
 
193
      {
 
194
        free_pam_response(resp, i);
 
195
        return PAM_CONV_ERR;
 
196
      }
 
197
 
 
198
      /* Read the answer */
 
199
      if ((pkt_len= data->vio->read_packet(data->vio, &pkt))
 
200
          < 0)
 
201
      {
 
202
        free_pam_response(resp, i);
 
203
        return PAM_CONV_ERR;
 
204
      }
 
205
 
 
206
      (*resp)[i].resp= malloc(pkt_len + 1);
 
207
      if ((*resp)[i].resp == NULL)
 
208
      {
 
209
        free_pam_response(resp, i);
 
210
        return PAM_BUF_ERR;
 
211
      }
 
212
 
 
213
      strncpy((*resp)[i].resp, (char *)pkt, pkt_len);
 
214
      (*resp)[i].resp[pkt_len]= '\0';
 
215
 
 
216
      if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
 
217
        data->info->password_used= PASSWORD_USED_YES;
 
218
 
 
219
      data->ptr= data->buf + 1;
 
220
    }
196
221
  }
197
222
  return PAM_SUCCESS;
198
223
}
201
226
                                              MYSQL_SERVER_AUTH_INFO *info)
202
227
{
203
228
  pam_handle_t *pam_handle;
204
 
  struct pam_conv conv_func_info= { &vio_server_conv, vio };
 
229
  struct pam_conv_data data= { vio, info, "", data.buf+1 };
 
230
  struct pam_conv conv_func_info= { &vio_server_conv, &data };
205
231
  int error;
206
232
  char *pam_mapped_user_name;
207
233
 
208
 
  /* Impossible to tell if PAM will use passwords or something else */
209
234
  info->password_used= PASSWORD_USED_NO_MENTION;
210
235
 
211
236
  error= pam_start(service_name,
242
267
    return CR_ERROR;
243
268
  }
244
269
 
245
 
  /* Send end-of-auth message */
246
 
  if (vio->write_packet(vio, (const unsigned char *)"\0", 1))
247
 
  {
248
 
    pam_end(pam_handle, error);
249
 
    return CR_ERROR;
250
 
  }
251
 
 
252
270
  /* Get the authenticated user name from PAM */
253
271
  error= pam_get_item(pam_handle, PAM_USER, (void *)&pam_mapped_user_name);
254
272
  if (error != PAM_SUCCESS)
277
295
static struct st_mysql_auth pam_auth_handler=
278
296
{
279
297
  MYSQL_AUTHENTICATION_INTERFACE_VERSION,
280
 
  "auth_pam",
 
298
  "dialog",
281
299
  &authenticate_user_with_pam_server
282
300
};
283
301
 
292
310
{
293
311
  MYSQL_AUTHENTICATION_PLUGIN,
294
312
  &pam_auth_handler,
295
 
  "auth_pam_server",
 
313
  "auth_pam",
296
314
  "Percona, Inc.",
297
315
  "PAM authentication plugin",
298
316
  PLUGIN_LICENSE_GPL,
327
345
#endif
328
346
}
329
347
mysql_declare_plugin_end;
330
 
 
331
 
/* The client plugin */
332
 
 
333
 
/* Returns malloc-allocated string, NULL in case of memory error. */
334
 
static char * prompt_echo_off (const char * prompt)
335
 
{
336
 
  /* TODO: getpass not thread safe.  Probably not a big deal in the mysql
337
 
     client program, but may be missing on non-glibc systems.  */
338
 
  char* getpass_input= getpass(prompt);
339
 
  return strdup(getpass_input);
340
 
}
341
 
 
342
 
/* Returns malloc-allocated string, NULL in case of memory or (unlikely)
343
 
I/O error.  */
344
 
static char * prompt_echo_on (const char * prompt)
345
 
{
346
 
  char* c;
347
 
  char fgets_buf[1024];
348
 
  fputs(prompt, stdout);
349
 
  fputc(' ', stdout);
350
 
  c= fgets(fgets_buf, sizeof(fgets_buf), stdin);
351
 
  if (c == NULL)
352
 
  {
353
 
    if (ferror(stdin))
354
 
      return NULL;
355
 
    fgets_buf[0]= '\0';
356
 
  }
357
 
  if ((c= strchr(fgets_buf, '\n')))
358
 
    *c= '\0';
359
 
  else
360
 
    fgets_buf[sizeof(fgets_buf) - 1]= '\0';
361
 
  return strdup(fgets_buf);
362
 
}
363
 
 
364
 
static void show_error(const char * message)
365
 
{
366
 
  fprintf(stderr, "ERROR %s\n", message);
367
 
}
368
 
 
369
 
static void show_info(const char * message)
370
 
{
371
 
  printf("%s\n", message);
372
 
}
373
 
 
374
 
static int authenticate_user_with_pam_client (MYSQL_PLUGIN_VIO *vio,
375
 
                                              struct st_mysql *mysql)
376
 
{
377
 
  return authenticate_user_with_pam_client_common (vio, mysql,
378
 
                                                   &prompt_echo_off,
379
 
                                                   &prompt_echo_on,
380
 
                                                   &show_error, &show_info);
381
 
}
382
 
 
383
 
mysql_declare_client_plugin(AUTHENTICATION)
384
 
  "auth_pam",
385
 
  "Percona, Inc.",
386
 
  "PAM authentication plugin",
387
 
  {0,1,0},
388
 
  "GPL",
389
 
  NULL,
390
 
  NULL, /* init */
391
 
  NULL, /* deinit */
392
 
  NULL, /* options */
393
 
  &authenticate_user_with_pam_client
394
 
mysql_end_client_plugin;