Merge from Subversion r50.
[nivanova/samba-autobuild/.git] / source3 / passdb / pdb_mysql.c
1 /*
2  * MySQL password backend for samba
3  * Copyright (C) Jelmer Vernooij 2002
4  * 
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  * 
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  * 
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 675
17  * Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include "includes.h"
21 #include <mysql/mysql.h>
22
23 #define CONFIG_TABLE_DEFAULT                            "user"
24 #define CONFIG_LOGON_TIME_DEFAULT                       "logon_time"
25 #define CONFIG_LOGOFF_TIME_DEFAULT                      "logoff_time"
26 #define CONFIG_KICKOFF_TIME_DEFAULT                     "kickoff_time"
27 #define CONFIG_PASS_LAST_SET_TIME_DEFAULT       "pass_last_set_time"
28 #define CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT     "pass_can_change_time"
29 #define CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT "pass_must_change_time"
30 #define CONFIG_USERNAME_DEFAULT                         "username"
31 #define CONFIG_DOMAIN_DEFAULT                           "domain"
32 #define CONFIG_NT_USERNAME_DEFAULT              "nt_username"
33 #define CONFIG_FULLNAME_DEFAULT                         "nt_fullname"
34 #define CONFIG_HOME_DIR_DEFAULT                         "home_dir"
35 #define CONFIG_DIR_DRIVE_DEFAULT                        "dir_drive"
36 #define CONFIG_LOGON_SCRIPT_DEFAULT                     "logon_script"
37 #define CONFIG_PROFILE_PATH_DEFAULT                     "profile_path"
38 #define CONFIG_ACCT_DESC_DEFAULT                        "acct_desc"
39 #define CONFIG_WORKSTATIONS_DEFAULT                     "workstations"
40 #define CONFIG_UNKNOWN_STR_DEFAULT                      "unknown_str"
41 #define CONFIG_MUNGED_DIAL_DEFAULT                      "munged_dial"
42 #define CONFIG_UID_DEFAULT                                      "uid"
43 #define CONFIG_GID_DEFAULT                                      "gid"
44 #define CONFIG_USER_SID_DEFAULT                         "user_sid"
45 #define CONFIG_GROUP_SID_DEFAULT                        "group_sid"
46 #define CONFIG_LM_PW_DEFAULT                            "lm_pw"
47 #define CONFIG_NT_PW_DEFAULT                            "nt_pw"
48 #define CONFIG_PLAIN_PW_DEFAULT                         "NULL"
49 #define CONFIG_ACCT_CTRL_DEFAULT                        "acct_ctrl"
50 #define CONFIG_UNKNOWN_3_DEFAULT                        "unknown_3"
51 #define CONFIG_LOGON_DIVS_DEFAULT                       "logon_divs"
52 #define CONFIG_HOURS_LEN_DEFAULT                        "hours_len"
53 #define CONFIG_UNKNOWN_5_DEFAULT                        "unknown_5"
54 #define CONFIG_UNKNOWN_6_DEFAULT                        "unknown_6"
55 #define CONFIG_HOST_DEFAULT                                     "localhost"
56 #define CONFIG_USER_DEFAULT                                     "samba"
57 #define CONFIG_PASS_DEFAULT                                     ""
58 #define CONFIG_PORT_DEFAULT                                     "3306"
59 #define CONFIG_DB_DEFAULT                                       "samba"
60
61 static int mysqlsam_debug_level = DBGC_ALL;
62
63 #undef DBGC_CLASS
64 #define DBGC_CLASS mysqlsam_debug_level
65
66 PDB_MODULE_VERSIONING_MAGIC
67
68 typedef struct pdb_mysql_data {
69         MYSQL *handle;
70         MYSQL_RES *pwent;
71         char *location;
72 } pdb_mysql_data;
73
74 /* Used to construct insert and update queries */
75
76 typedef struct pdb_mysql_query {
77         char update;
78         TALLOC_CTX *mem_ctx;
79         char *part1;
80         char *part2;
81 } pdb_mysql_query;
82 #define SET_DATA(data,methods) { \
83         if(!methods){ \
84                 DEBUG(0, ("invalid methods!\n")); \
85                         return NT_STATUS_INVALID_PARAMETER; \
86         } \
87         data = (struct pdb_mysql_data *)methods->private_data; \
88                 if(!data || !(data->handle)){ \
89                         DEBUG(0, ("invalid handle!\n")); \
90                                 return NT_STATUS_INVALID_HANDLE; \
91                 } \
92 }
93
94 static void pdb_mysql_int_field(struct pdb_methods *m,
95                                         struct pdb_mysql_query *q, char *name, int value)
96 {
97         if (!name || strchr(name, '\''))
98                 return;                 /* This field shouldn't be set by us */
99
100         if (q->update) {
101                 q->part1 =
102                         talloc_asprintf_append(q->mem_ctx, q->part1,
103                                                                    "%s = %d,", name, value);
104         } else {
105                 q->part1 =
106                         talloc_asprintf_append(q->mem_ctx, q->part1, "%s,", name);
107                 q->part2 =
108                         talloc_asprintf_append(q->mem_ctx, q->part2, "%d,", value);
109         }
110 }
111
112 static NTSTATUS pdb_mysql_string_field(struct pdb_methods *methods,
113                                            struct pdb_mysql_query *q,
114                                            char *name, const char *value)
115 {
116         char *esc_value;
117         struct pdb_mysql_data *data;
118         char *tmp_value;
119
120         SET_DATA(data, methods);
121
122         if (!name || !value || !strcmp(value, "") || strchr(name, '\''))
123                 return NT_STATUS_INVALID_PARAMETER;   /* This field shouldn't be set by module */
124
125         esc_value = malloc(strlen(value) * 2 + 1);
126
127         tmp_value = smb_xstrdup(value);
128         mysql_real_escape_string(data->handle, esc_value, tmp_value,
129                                                          strlen(tmp_value));
130         SAFE_FREE(tmp_value);
131
132         if (q->update) {
133                 q->part1 =
134                         talloc_asprintf_append(q->mem_ctx, q->part1,
135                                                                    "%s = '%s',", name, esc_value);
136         } else {
137                 q->part1 =
138                         talloc_asprintf_append(q->mem_ctx, q->part1, "%s,", name);
139                 q->part2 =
140                         talloc_asprintf_append(q->mem_ctx, q->part2, "'%s',",
141                                                                    esc_value);
142         }
143
144         SAFE_FREE(esc_value);
145
146         return NT_STATUS_OK;
147 }
148
149 static char * config_value(pdb_mysql_data * data, char *name, char *default_value)
150 {
151         if (lp_parm_string(NULL, data->location, name))
152                 return lp_parm_string(NULL, data->location, name);
153
154         return default_value;
155 }
156
157 static char * config_value_write(pdb_mysql_data * data, char *name, char *default_value) {
158         char *v = config_value(data, name, NULL);
159         char *swrite;
160
161         if (!v)
162                 return default_value;
163
164         swrite = strchr(v, ':');
165
166         /* Default to the same field as read field */
167         if (!swrite)
168                 return v;
169
170         swrite++;
171
172         /* If the field is 0 chars long, we shouldn't write to it */
173         if (!strlen(swrite) || !strcmp(swrite, "NULL"))
174                 return NULL;
175
176         /* Otherwise, use the additionally specified */
177         return swrite;
178 }
179
180 static const char * config_value_read(pdb_mysql_data * data, char *name, char *default_value)
181 {
182         char *v = config_value(data, name, NULL);
183         char *swrite;
184
185         if (!v)
186                 return default_value;
187
188         swrite = strchr(v, ':');
189
190         /* If no write is specified, there are no problems */
191         if (!swrite) {
192                 if (strlen(v) == 0)
193                         return "NULL";
194                 return v;
195         }
196
197         /* Otherwise, we have to cut the ':write_part' */
198         *swrite = '\0';
199         if (strlen(v) == 0)
200                 return "NULL";
201
202         return v;
203 }
204
205 /* Wrapper for atol that returns 0 if 'a' points to NULL */
206 static long xatol(char *a)
207 {
208         long ret = 0;
209
210         if (a != NULL)
211                 ret = atol(a);
212
213         return ret;
214 }
215
216 static NTSTATUS row_to_sam_account(MYSQL_RES * r, SAM_ACCOUNT * u)
217 {
218         MYSQL_ROW row;
219         pstring temp;
220         unsigned int num_fields;
221         DOM_SID sid;
222
223         num_fields = mysql_num_fields(r);
224         row = mysql_fetch_row(r);
225         if (!row)
226                 return NT_STATUS_INVALID_PARAMETER;
227
228         pdb_set_logon_time(u, xatol(row[0]), PDB_SET);
229         pdb_set_logoff_time(u, xatol(row[1]), PDB_SET);
230         pdb_set_kickoff_time(u, xatol(row[2]), PDB_SET);
231         pdb_set_pass_last_set_time(u, xatol(row[3]), PDB_SET);
232         pdb_set_pass_can_change_time(u, xatol(row[4]), PDB_SET);
233         pdb_set_pass_must_change_time(u, xatol(row[5]), PDB_SET);
234         pdb_set_username(u, row[6], PDB_SET);
235         pdb_set_domain(u, row[7], PDB_SET);
236         pdb_set_nt_username(u, row[8], PDB_SET);
237         pdb_set_fullname(u, row[9], PDB_SET);
238         pdb_set_homedir(u, row[10], PDB_SET);
239         pdb_set_dir_drive(u, row[11], PDB_SET);
240         pdb_set_logon_script(u, row[12], PDB_SET);
241         pdb_set_profile_path(u, row[13], PDB_SET);
242         pdb_set_acct_desc(u, row[14], PDB_SET);
243         pdb_set_workstations(u, row[15], PDB_SET);
244         pdb_set_unknown_str(u, row[16], PDB_SET);
245         pdb_set_munged_dial(u, row[17], PDB_SET);
246
247         if (row[18])
248                 pdb_set_uid(u, xatol(row[18]), PDB_SET);
249         if (row[19])
250                 pdb_set_gid(u, xatol(row[19]), PDB_SET);
251
252         string_to_sid(&sid, row[20]);
253         pdb_set_user_sid(u, &sid, PDB_SET);
254         string_to_sid(&sid, row[21]);
255         pdb_set_group_sid(u, &sid, PDB_SET);
256
257         if (pdb_gethexpwd(row[22], temp), PDB_SET)
258                 pdb_set_lanman_passwd(u, temp, PDB_SET);
259         if (pdb_gethexpwd(row[23], temp), PDB_SET)
260                 pdb_set_nt_passwd(u, temp, PDB_SET);
261
262         /* Only use plaintext password storage when lanman and nt are
263          * NOT used */
264         if (!row[22] || !row[23])
265                 pdb_set_plaintext_passwd(u, row[24]);
266
267         pdb_set_acct_ctrl(u, xatol(row[25]), PDB_SET);
268         pdb_set_unknown_3(u, xatol(row[26]), PDB_SET);
269         pdb_set_logon_divs(u, xatol(row[27]), PDB_SET);
270         pdb_set_hours_len(u, xatol(row[28]), PDB_SET);
271         pdb_set_unknown_5(u, xatol(row[29]), PDB_SET);
272         pdb_set_unknown_6(u, xatol(row[30]), PDB_SET);
273
274         return NT_STATUS_OK;
275 }
276
277 static NTSTATUS mysqlsam_setsampwent(struct pdb_methods *methods, BOOL update)
278 {
279         struct pdb_mysql_data *data =
280                 (struct pdb_mysql_data *) methods->private_data;
281         char *query;
282         int ret;
283
284         if (!data || !(data->handle)) {
285                 DEBUG(0, ("invalid handle!\n"));
286                 return NT_STATUS_INVALID_HANDLE;
287         }
288
289         asprintf(&query,
290                          "SELECT %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s FROM %s",
291                          config_value_read(data, "logon time column",
292                                                            CONFIG_LOGON_TIME_DEFAULT),
293                          config_value_read(data, "logoff time column",
294                                                            CONFIG_LOGOFF_TIME_DEFAULT),
295                          config_value_read(data, "kickoff time column",
296                                                            CONFIG_KICKOFF_TIME_DEFAULT),
297                          config_value_read(data, "pass last set time column",
298                                                            CONFIG_PASS_LAST_SET_TIME_DEFAULT),
299                          config_value_read(data, "pass can change time column",
300                                                            CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT),
301                          config_value_read(data, "pass must change time column",
302                                                            CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT),
303                          config_value_read(data, "username column",
304                                                            CONFIG_USERNAME_DEFAULT),
305                          config_value_read(data, "domain column",
306                                                            CONFIG_DOMAIN_DEFAULT),
307                          config_value_read(data, "nt username column",
308                                                            CONFIG_NT_USERNAME_DEFAULT),
309                          config_value_read(data, "fullname column",
310                                                            CONFIG_FULLNAME_DEFAULT),
311                          config_value_read(data, "home dir column",
312                                                            CONFIG_HOME_DIR_DEFAULT),
313                          config_value_read(data, "dir drive column",
314                                                            CONFIG_DIR_DRIVE_DEFAULT),
315                          config_value_read(data, "logon script column",
316                                                            CONFIG_LOGON_SCRIPT_DEFAULT),
317                          config_value_read(data, "profile path column",
318                                                            CONFIG_PROFILE_PATH_DEFAULT),
319                          config_value_read(data, "acct desc column",
320                                                            CONFIG_ACCT_DESC_DEFAULT),
321                          config_value_read(data, "workstations column",
322                                                            CONFIG_WORKSTATIONS_DEFAULT),
323                          config_value_read(data, "unknown string column",
324                                                            CONFIG_UNKNOWN_STR_DEFAULT),
325                          config_value_read(data, "munged dial column",
326                                                            CONFIG_MUNGED_DIAL_DEFAULT),
327                          config_value_read(data, "uid column", CONFIG_UID_DEFAULT),
328                          config_value_read(data, "gid column", CONFIG_GID_DEFAULT),
329                          config_value_read(data, "user sid column",
330                                                            CONFIG_USER_SID_DEFAULT),
331                          config_value_read(data, "group sid column",
332                                                            CONFIG_GROUP_SID_DEFAULT),
333                          config_value_read(data, "lanman pass column",
334                                                            CONFIG_LM_PW_DEFAULT),
335                          config_value_read(data, "nt pass column",
336                                                            CONFIG_NT_PW_DEFAULT),
337                          config_value_read(data, "plain pass column",
338                                                            CONFIG_PLAIN_PW_DEFAULT),
339                          config_value_read(data, "acct ctrl column",
340                                                            CONFIG_ACCT_CTRL_DEFAULT),
341                          config_value_read(data, "unknown 3 column",
342                                                            CONFIG_UNKNOWN_3_DEFAULT),
343                          config_value_read(data, "logon divs column",
344                                                            CONFIG_LOGON_DIVS_DEFAULT),
345                          config_value_read(data, "hours len column",
346                                                            CONFIG_HOURS_LEN_DEFAULT),
347                          config_value_read(data, "unknown 5 column",
348                                                            CONFIG_UNKNOWN_5_DEFAULT),
349                          config_value_read(data, "unknown 6 column",
350                                                            CONFIG_UNKNOWN_6_DEFAULT),
351                          config_value(data, "table", CONFIG_TABLE_DEFAULT)
352                                  );
353         DEBUG(5, ("Executing query %s\n", query));
354         
355         ret = mysql_query(data->handle, query);
356         SAFE_FREE(query);
357
358         if (ret) {
359                 DEBUG(0,
360                            ("Error executing MySQL query %s\n", mysql_error(data->handle)));
361                 return NT_STATUS_UNSUCCESSFUL;
362         }
363
364         data->pwent = mysql_store_result(data->handle);
365
366         if (data->pwent == NULL) {
367                 DEBUG(0,
368                         ("Error storing results: %s\n", mysql_error(data->handle)));
369                 return NT_STATUS_UNSUCCESSFUL;
370         }
371         
372         DEBUG(5,
373                 ("mysqlsam_setsampwent succeeded(%lu results)!\n",
374                                 mysql_num_rows(data->pwent)));
375         
376         return NT_STATUS_OK;
377 }
378
379 /***************************************************************
380   End enumeration of the passwd list.
381  ****************************************************************/
382
383 static void mysqlsam_endsampwent(struct pdb_methods *methods)
384 {
385         struct pdb_mysql_data *data =
386                 (struct pdb_mysql_data *) methods->private_data;
387
388         if (data == NULL) {
389                 DEBUG(0, ("invalid handle!\n"));
390                 return;
391         }
392
393         if (data->pwent != NULL)
394                 mysql_free_result(data->pwent);
395
396         data->pwent = NULL;
397
398         DEBUG(5, ("mysql_endsampwent called\n"));
399 }
400
401 /*****************************************************************
402   Get one SAM_ACCOUNT from the list (next in line)
403  *****************************************************************/
404
405 static NTSTATUS mysqlsam_getsampwent(struct pdb_methods *methods, SAM_ACCOUNT * user)
406 {
407         struct pdb_mysql_data *data;
408
409         SET_DATA(data, methods);
410
411         if (data->pwent == NULL) {
412                 DEBUG(0, ("invalid pwent\n"));
413                 return NT_STATUS_INVALID_PARAMETER;
414         }
415
416         return row_to_sam_account(data->pwent, user);
417 }
418
419 static NTSTATUS mysqlsam_select_by_field(struct pdb_methods * methods, SAM_ACCOUNT * user,
420                                                  const char *field, const char *sname)
421 {
422         char *esc_sname;
423         char *query;
424         NTSTATUS ret;
425         MYSQL_RES *res;
426         int mysql_ret;
427         struct pdb_mysql_data *data;
428         char *tmp_sname;
429
430         SET_DATA(data, methods);
431
432         esc_sname = malloc(strlen(sname) * 2 + 1);
433         if (!esc_sname) {
434                 return NT_STATUS_NO_MEMORY; 
435         }
436
437         DEBUG(5,
438                   ("mysqlsam_select_by_field: getting data where %s = %s(nonescaped)\n",
439                    field, sname));
440
441         tmp_sname = smb_xstrdup(sname);
442         
443         /* Escape sname */
444         mysql_real_escape_string(data->handle, esc_sname, tmp_sname,
445                                                          strlen(tmp_sname));
446
447         SAFE_FREE(tmp_sname);
448
449         if (user == NULL) {
450                 DEBUG(0, ("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n"));
451                 SAFE_FREE(esc_sname);
452                 return NT_STATUS_INVALID_PARAMETER;
453         }
454
455         asprintf(&query,
456                          "SELECT %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s FROM %s WHERE %s = '%s'",
457                          config_value_read(data, "logon time column",
458                                                            CONFIG_LOGON_TIME_DEFAULT),
459                          config_value_read(data, "logoff time column",
460                                                            CONFIG_LOGOFF_TIME_DEFAULT),
461                          config_value_read(data, "kickoff time column",
462                                                            CONFIG_KICKOFF_TIME_DEFAULT),
463                          config_value_read(data, "pass last set time column",
464                                                            CONFIG_PASS_LAST_SET_TIME_DEFAULT),
465                          config_value_read(data, "pass can change time column",
466                                                            CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT),
467                          config_value_read(data, "pass must change time column",
468                                                            CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT),
469                          config_value_read(data, "username column",
470                                                            CONFIG_USERNAME_DEFAULT),
471                          config_value_read(data, "domain column",
472                                                            CONFIG_DOMAIN_DEFAULT),
473                          config_value_read(data, "nt username column",
474                                                            CONFIG_NT_USERNAME_DEFAULT),
475                          config_value_read(data, "fullname column",
476                                                            CONFIG_FULLNAME_DEFAULT),
477                          config_value_read(data, "home dir column",
478                                                            CONFIG_HOME_DIR_DEFAULT),
479                          config_value_read(data, "dir drive column",
480                                                            CONFIG_DIR_DRIVE_DEFAULT),
481                          config_value_read(data, "logon script column",
482                                                            CONFIG_LOGON_SCRIPT_DEFAULT),
483                          config_value_read(data, "profile path column",
484                                                            CONFIG_PROFILE_PATH_DEFAULT),
485                          config_value_read(data, "acct desc column",
486                                                            CONFIG_ACCT_DESC_DEFAULT),
487                          config_value_read(data, "workstations column",
488                                                            CONFIG_WORKSTATIONS_DEFAULT),
489                          config_value_read(data, "unknown string column",
490                                                            CONFIG_UNKNOWN_STR_DEFAULT),
491                          config_value_read(data, "munged dial column",
492                                                            CONFIG_MUNGED_DIAL_DEFAULT),
493                          config_value_read(data, "uid column", CONFIG_UID_DEFAULT),
494                          config_value_read(data, "gid column", CONFIG_GID_DEFAULT),
495                          config_value_read(data, "user sid column",
496                                                            CONFIG_USER_SID_DEFAULT),
497                          config_value_read(data, "group sid column",
498                                                            CONFIG_GROUP_SID_DEFAULT),
499                          config_value_read(data, "lanman pass column",
500                                                            CONFIG_LM_PW_DEFAULT),
501                          config_value_read(data, "nt pass column",
502                                                            CONFIG_NT_PW_DEFAULT),
503                          config_value_read(data, "plain pass column",
504                                                            CONFIG_PLAIN_PW_DEFAULT),
505                          config_value_read(data, "acct ctrl column",
506                                                            CONFIG_ACCT_CTRL_DEFAULT),
507                          config_value_read(data, "unknown 3 column",
508                                                            CONFIG_UNKNOWN_3_DEFAULT),
509                          config_value_read(data, "logon divs column",
510                                                            CONFIG_LOGON_DIVS_DEFAULT),
511                          config_value_read(data, "hours len column",
512                                                            CONFIG_HOURS_LEN_DEFAULT),
513                          config_value_read(data, "unknown 5 column",
514                                                            CONFIG_UNKNOWN_5_DEFAULT),
515                          config_value_read(data, "unknown 6 column",
516                                                            CONFIG_UNKNOWN_6_DEFAULT),
517                          config_value(data, "table", CONFIG_TABLE_DEFAULT), field,
518                          esc_sname);
519         
520         SAFE_FREE(esc_sname);
521
522         DEBUG(5, ("Executing query %s\n", query));
523         
524         mysql_ret = mysql_query(data->handle, query);
525         
526         SAFE_FREE(query);
527         
528         if (mysql_ret) {
529                 DEBUG(0,
530                         ("Error while executing MySQL query %s\n", 
531                                 mysql_error(data->handle)));
532                 return NT_STATUS_UNSUCCESSFUL;
533         }
534         
535         res = mysql_store_result(data->handle);
536         if (res == NULL) {
537                 DEBUG(0,
538                         ("Error storing results: %s\n", mysql_error(data->handle)));
539                 return NT_STATUS_UNSUCCESSFUL;
540         }
541         
542         ret = row_to_sam_account(res, user);
543         mysql_free_result(res);
544
545         return ret;
546 }
547
548 /******************************************************************
549   Lookup a name in the SAM database
550  ******************************************************************/
551
552 static NTSTATUS mysqlsam_getsampwnam(struct pdb_methods *methods, SAM_ACCOUNT * user,
553                                          const char *sname)
554 {
555         struct pdb_mysql_data *data;
556
557         SET_DATA(data, methods);
558
559         if (!sname) {
560                 DEBUG(0, ("invalid name specified"));
561                 return NT_STATUS_INVALID_PARAMETER;
562         }
563
564         return mysqlsam_select_by_field(methods, user,
565                         config_value_read(data, "username column",
566                                 CONFIG_USERNAME_DEFAULT), sname);
567 }
568
569
570 /***************************************************************************
571   Search by sid
572  **************************************************************************/
573
574 static NTSTATUS mysqlsam_getsampwsid(struct pdb_methods *methods, SAM_ACCOUNT * user,
575                                          const DOM_SID * sid)
576 {
577         struct pdb_mysql_data *data;
578         fstring sid_str;
579
580         SET_DATA(data, methods);
581
582         sid_to_string(sid_str, sid);
583
584         return mysqlsam_select_by_field(methods, user,
585                         config_value_read(data, "user sid column",
586                                 CONFIG_USER_SID_DEFAULT), sid_str);
587 }
588
589 /***************************************************************************
590   Delete a SAM_ACCOUNT
591  ****************************************************************************/
592
593 static NTSTATUS mysqlsam_delete_sam_account(struct pdb_methods *methods,
594                                                         SAM_ACCOUNT * sam_pass)
595 {
596         const char *sname = pdb_get_username(sam_pass);
597         char *esc;
598         char *query;
599         int ret;
600         struct pdb_mysql_data *data;
601         char *tmp_sname;
602
603         SET_DATA(data, methods);
604
605         if (!methods) {
606                 DEBUG(0, ("invalid methods!\n"));
607                 return NT_STATUS_INVALID_PARAMETER;
608         }
609
610         data = (struct pdb_mysql_data *) methods->private_data;
611         if (!data || !(data->handle)) {
612                 DEBUG(0, ("invalid handle!\n"));
613                 return NT_STATUS_INVALID_HANDLE;
614         }
615
616         if (!sname) {
617                 DEBUG(0, ("invalid name specified\n"));
618                 return NT_STATUS_INVALID_PARAMETER;
619         }
620
621         /* Escape sname */
622         esc = malloc(strlen(sname) * 2 + 1);
623         if (!esc) {
624                 DEBUG(0, ("Can't allocate memory to store escaped name\n"));
625                 return NT_STATUS_NO_MEMORY;
626         }
627         
628         tmp_sname = smb_xstrdup(sname);
629         
630         mysql_real_escape_string(data->handle, esc, tmp_sname,
631                                                          strlen(tmp_sname));
632
633         SAFE_FREE(tmp_sname);
634
635         asprintf(&query, "DELETE FROM %s WHERE %s = '%s'",
636                          config_value(data, "table", CONFIG_TABLE_DEFAULT),
637                          config_value_read(data, "username column",
638                                                            CONFIG_USERNAME_DEFAULT), esc);
639
640         SAFE_FREE(esc);
641
642         ret = mysql_query(data->handle, query);
643
644         SAFE_FREE(query);
645
646         if (ret) {
647                 DEBUG(0,
648                           ("Error while executing query: %s\n",
649                            mysql_error(data->handle)));
650                 return NT_STATUS_UNSUCCESSFUL;
651         }
652
653         DEBUG(5, ("User '%s' deleted\n", sname));
654         return NT_STATUS_OK;
655 }
656
657 static NTSTATUS mysqlsam_replace_sam_account(struct pdb_methods *methods,
658                                                          const SAM_ACCOUNT * newpwd, char isupdate)
659 {
660         pstring temp;
661         struct pdb_mysql_data *data;
662         pdb_mysql_query query;
663         fstring sid_str;
664
665         if (!methods) {
666                 DEBUG(0, ("invalid methods!\n"));
667                 return NT_STATUS_INVALID_PARAMETER;
668         }
669
670         data = (struct pdb_mysql_data *) methods->private_data;
671         if (data == NULL || data->handle == NULL) {
672                 DEBUG(0, ("invalid handle!\n"));
673                 return NT_STATUS_INVALID_HANDLE;
674         }
675         query.update = isupdate;
676
677         /* I know this is somewhat overkill but only the talloc 
678          * functions have asprint_append and the 'normal' asprintf 
679          * is a GNU extension */
680         query.mem_ctx = talloc_init("mysqlsam_replace_sam_account");
681         query.part2 = talloc_asprintf(query.mem_ctx, "%s", "");
682         if (query.update) {
683                 query.part1 =
684                         talloc_asprintf(query.mem_ctx, "UPDATE %s SET ",
685                                                         config_value(data, "table",
686                                                                                  CONFIG_TABLE_DEFAULT));
687         } else {
688                 query.part1 =
689                         talloc_asprintf(query.mem_ctx, "INSERT INTO %s (",
690                                                         config_value(data, "table",
691                                                                                  CONFIG_TABLE_DEFAULT));
692         }
693
694         pdb_mysql_int_field(methods, &query,
695                                                 config_value_write(data, "acct ctrl column",
696                                                                                    CONFIG_ACCT_CTRL_DEFAULT),
697                                                 pdb_get_acct_ctrl(newpwd));
698
699         if (pdb_get_init_flags(newpwd, PDB_LOGONTIME) != PDB_DEFAULT) {
700                 pdb_mysql_int_field(methods, &query,
701                                                         config_value_write(data,
702                                                                                            "logon time column",
703                                                                                            CONFIG_LOGON_TIME_DEFAULT),
704                                                         pdb_get_logon_time(newpwd));
705         }
706
707         if (pdb_get_init_flags(newpwd, PDB_LOGOFFTIME) != PDB_DEFAULT) {
708                 pdb_mysql_int_field(methods, &query,
709                                                         config_value_write(data,
710                                                                                            "logoff time column",
711                                                                                            CONFIG_LOGOFF_TIME_DEFAULT),
712                                                         pdb_get_logoff_time(newpwd));
713         }
714
715         if (pdb_get_init_flags(newpwd, PDB_KICKOFFTIME) != PDB_DEFAULT) {
716                 pdb_mysql_int_field(methods, &query,
717                                                         config_value_write(data,
718                                                                                            "kickoff time column",
719                                                                                            CONFIG_KICKOFF_TIME_DEFAULT),
720                                                         pdb_get_kickoff_time(newpwd));
721         }
722
723         if (pdb_get_init_flags(newpwd, PDB_CANCHANGETIME) != PDB_DEFAULT) {
724                 pdb_mysql_int_field(methods, &query,
725                                                         config_value_write(data,
726                                                                                            "pass can change time column",
727                                                                                            CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT),
728                                                         pdb_get_pass_can_change_time(newpwd));
729         }
730
731         if (pdb_get_init_flags(newpwd, PDB_MUSTCHANGETIME) != PDB_DEFAULT) {
732                 pdb_mysql_int_field(methods, &query,
733                                                         config_value_write(data,
734                                                                                            "pass must change time column",
735                                                                                            CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT),
736                                                         pdb_get_pass_must_change_time(newpwd));
737         }
738
739         if (pdb_get_pass_last_set_time(newpwd)) {
740                 pdb_mysql_int_field(methods, &query,
741                                                         config_value_write(data,
742                                                                                            "pass last set time column",
743                                                                                            CONFIG_PASS_LAST_SET_TIME_DEFAULT),
744                                                         pdb_get_pass_last_set_time(newpwd));
745         }
746
747         if (pdb_get_hours_len(newpwd)) {
748                 pdb_mysql_int_field(methods, &query,
749                                                         config_value_write(data,
750                                                                                            "hours len column",
751                                                                                            CONFIG_HOURS_LEN_DEFAULT),
752                                                         pdb_get_hours_len(newpwd));
753         }
754
755         if (pdb_get_logon_divs(newpwd)) {
756                 pdb_mysql_int_field(methods, &query,
757                                                         config_value_write(data,
758                                                                                            "logon divs column",
759                                                                                            CONFIG_LOGON_DIVS_DEFAULT),
760                                                         pdb_get_logon_divs(newpwd));
761         }
762
763         if (pdb_get_init_flags(newpwd, PDB_UID) != PDB_DEFAULT) {
764                 pdb_mysql_int_field(methods, &query,
765                                                         config_value_write(data, "uid column",
766                                                                                            CONFIG_UID_DEFAULT),
767                                                         pdb_get_uid(newpwd));
768         }
769
770         if (pdb_get_init_flags(newpwd, PDB_GID) != PDB_DEFAULT) {
771                 pdb_mysql_int_field(methods, &query,
772                                                         config_value_write(data, "gid column",
773                                                                                            CONFIG_GID_DEFAULT),
774                                                         pdb_get_gid(newpwd));
775         }
776
777         pdb_mysql_string_field(methods, &query,
778                                                    config_value_write(data, "user sid column",
779                                                                                           CONFIG_USER_SID_DEFAULT),
780                                                    sid_to_string(sid_str, 
781                                                                                  pdb_get_user_sid(newpwd)));
782
783         pdb_mysql_string_field(methods, &query,
784                                                    config_value_write(data, "group sid column",
785                                                                                           CONFIG_GROUP_SID_DEFAULT),
786                                                    sid_to_string(sid_str,
787                                                                                  pdb_get_group_sid(newpwd)));
788
789         pdb_mysql_string_field(methods, &query,
790                                                    config_value_write(data, "username column",
791                                                                                           CONFIG_USERNAME_DEFAULT),
792                                                    pdb_get_username(newpwd));
793
794         pdb_mysql_string_field(methods, &query,
795                                                    config_value_write(data, "domain column",
796                                                                                           CONFIG_DOMAIN_DEFAULT),
797                                                    pdb_get_domain(newpwd));
798
799         pdb_mysql_string_field(methods, &query,
800                                                    config_value_write(data,
801                                                                                           "nt username column",
802                                                                                           CONFIG_NT_USERNAME_DEFAULT),
803                                                    pdb_get_nt_username(newpwd));
804
805         pdb_mysql_string_field(methods, &query,
806                                                    config_value_write(data, "fullname column",
807                                                                                           CONFIG_FULLNAME_DEFAULT),
808                                                    pdb_get_fullname(newpwd));
809
810         pdb_mysql_string_field(methods, &query,
811                                                    config_value_write(data,
812                                                                                           "logon script column",
813                                                                                           CONFIG_LOGON_SCRIPT_DEFAULT),
814                                                    pdb_get_logon_script(newpwd));
815
816         pdb_mysql_string_field(methods, &query,
817                                                    config_value_write(data,
818                                                                                           "profile path column",
819                                                                                           CONFIG_PROFILE_PATH_DEFAULT),
820                                                    pdb_get_profile_path(newpwd));
821
822         pdb_mysql_string_field(methods, &query,
823                                                    config_value_write(data, "dir drive column",
824                                                                                           CONFIG_DIR_DRIVE_DEFAULT),
825                                                    pdb_get_dir_drive(newpwd));
826
827         pdb_mysql_string_field(methods, &query,
828                                                    config_value_write(data, "home dir column",
829                                                                                           CONFIG_HOME_DIR_DEFAULT),
830                                                    pdb_get_homedir(newpwd));
831
832         pdb_mysql_string_field(methods, &query,
833                                                    config_value_write(data,
834                                                                                           "workstations column",
835                                                                                           CONFIG_WORKSTATIONS_DEFAULT),
836                                                    pdb_get_workstations(newpwd));
837
838         pdb_mysql_string_field(methods, &query,
839                                                    config_value_write(data,
840                                                                                           "unknown string column",
841                                                                                           CONFIG_UNKNOWN_STR_DEFAULT),
842                                                    pdb_get_workstations(newpwd));
843
844         pdb_sethexpwd(temp, pdb_get_lanman_passwd(newpwd),
845                                   pdb_get_acct_ctrl(newpwd));
846         pdb_mysql_string_field(methods, &query,
847                                                    config_value_write(data,
848                                                                                           "lanman pass column",
849                                                                                           CONFIG_LM_PW_DEFAULT), temp);
850
851         pdb_sethexpwd(temp, pdb_get_nt_passwd(newpwd),
852                                   pdb_get_acct_ctrl(newpwd));
853         pdb_mysql_string_field(methods, &query,
854                                                    config_value_write(data, "nt pass column",
855                                                                                           CONFIG_NT_PW_DEFAULT), temp);
856
857         if (query.update) {
858                 query.part1[strlen(query.part1) - 1] = '\0';
859                 query.part1 =
860                         talloc_asprintf_append(query.mem_ctx, query.part1,
861                                                                    " WHERE %s = '%s'",
862                                                                    config_value_read(data,
863                                                                                                          "user sid column",
864                                                                                                          CONFIG_USER_SID_DEFAULT),
865                                                                    sid_to_string(sid_str, pdb_get_user_sid (newpwd)));
866         } else {
867                 query.part2[strlen(query.part2) - 1] = ')';
868                 query.part1[strlen(query.part1) - 1] = ')';
869                 query.part1 =
870                         talloc_asprintf_append(query.mem_ctx, query.part1,
871                                                                    " VALUES (%s", query.part2);
872         }
873
874         DEBUG(0, ("%s\n", query.part1));
875         /* Execute the query */
876         if (mysql_query(data->handle, query.part1)) {
877                 DEBUG(0,
878                           ("Error executing %s, %s\n", query.part1,
879                            mysql_error(data->handle)));
880                 return NT_STATUS_INVALID_PARAMETER;
881         }
882         talloc_destroy(query.mem_ctx);
883         return NT_STATUS_OK;
884 }
885
886 static NTSTATUS mysqlsam_add_sam_account(struct pdb_methods *methods, SAM_ACCOUNT * newpwd)
887 {
888         return mysqlsam_replace_sam_account(methods, newpwd, 0);
889 }
890
891 static NTSTATUS mysqlsam_update_sam_account(struct pdb_methods *methods,
892                                                         SAM_ACCOUNT * newpwd)
893 {
894         return mysqlsam_replace_sam_account(methods, newpwd, 1);
895 }
896
897 static NTSTATUS mysqlsam_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
898                                 DOM_SID sid, BOOL with_priv)
899 {
900         return get_group_map_from_sid(sid, map, with_priv) ?
901                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
902 }
903
904 static NTSTATUS mysqlsam_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
905                                 gid_t gid, BOOL with_priv)
906 {
907         return get_group_map_from_gid(gid, map, with_priv) ?
908                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
909 }
910
911 static NTSTATUS mysqlsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
912                                 char *name, BOOL with_priv)
913 {
914         return get_group_map_from_ntname(name, map, with_priv) ?
915                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
916 }
917
918 static NTSTATUS mysqlsam_add_group_mapping_entry(struct pdb_methods *methods,
919                                                GROUP_MAP *map)
920 {
921         return add_mapping_entry(map, TDB_INSERT) ?
922                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
923 }
924
925 static NTSTATUS mysqlsam_update_group_mapping_entry(struct pdb_methods *methods,
926                                                   GROUP_MAP *map)
927 {
928         return add_mapping_entry(map, TDB_REPLACE) ?
929                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
930 }
931
932 static NTSTATUS mysqlsam_delete_group_mapping_entry(struct pdb_methods *methods,
933                                                   DOM_SID sid)
934 {
935         return group_map_remove(sid) ?
936                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
937 }
938
939 static NTSTATUS mysqlsam_enum_group_mapping(struct pdb_methods *methods,
940                                           enum SID_NAME_USE sid_name_use,
941                                           GROUP_MAP **rmap, int *num_entries,
942                                           BOOL unix_only, BOOL with_priv)
943 {
944         return enum_group_mapping(sid_name_use, rmap, num_entries, unix_only,
945                                   with_priv) ?
946                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
947 }
948
949
950 NTSTATUS pdb_init(PDB_CONTEXT * pdb_context, PDB_METHODS ** pdb_method,
951                  char *location)
952 {
953         NTSTATUS nt_status;
954         struct pdb_mysql_data *data;
955
956         mysqlsam_debug_level = debug_add_class("mysqlsam");
957         if (mysqlsam_debug_level == -1) {
958                 mysqlsam_debug_level = DBGC_ALL;
959                 DEBUG(0,
960                           ("mysqlsam: Couldn't register custom debugging class!\n"));
961         }
962
963         if (!pdb_context) {
964                 DEBUG(0, ("invalid pdb_methods specified\n"));
965                 return NT_STATUS_UNSUCCESSFUL;
966         }
967
968         if (!NT_STATUS_IS_OK
969                 (nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
970                 return nt_status;
971         }
972
973         (*pdb_method)->name = "mysqlsam";
974
975         (*pdb_method)->setsampwent = mysqlsam_setsampwent;
976         (*pdb_method)->endsampwent = mysqlsam_endsampwent;
977         (*pdb_method)->getsampwent = mysqlsam_getsampwent;
978         (*pdb_method)->getsampwnam = mysqlsam_getsampwnam;
979         (*pdb_method)->getsampwsid = mysqlsam_getsampwsid;
980         (*pdb_method)->add_sam_account = mysqlsam_add_sam_account;
981         (*pdb_method)->update_sam_account = mysqlsam_update_sam_account;
982         (*pdb_method)->delete_sam_account = mysqlsam_delete_sam_account;
983         (*pdb_method)->getgrsid = mysqlsam_getgrsid;
984         (*pdb_method)->getgrgid = mysqlsam_getgrgid;
985         (*pdb_method)->getgrnam = mysqlsam_getgrnam;
986         (*pdb_method)->add_group_mapping_entry = mysqlsam_add_group_mapping_entry;
987         (*pdb_method)->update_group_mapping_entry = mysqlsam_update_group_mapping_entry;
988         (*pdb_method)->delete_group_mapping_entry = mysqlsam_delete_group_mapping_entry;
989         (*pdb_method)->enum_group_mapping = mysqlsam_enum_group_mapping;
990
991         data = talloc(pdb_context->mem_ctx, sizeof(struct pdb_mysql_data));
992         (*pdb_method)->private_data = data;
993         data->handle = NULL;
994         data->pwent = NULL;
995
996         if (!location) {
997                 DEBUG(0, ("No identifier specified. See README for details\n"));
998                 return NT_STATUS_INVALID_PARAMETER;
999         }
1000
1001         data->location = smb_xstrdup(location);
1002
1003         DEBUG(1,
1004                   ("Connecting to database server, host: %s, user: %s, password: %s, database: %s, port: %ld\n",
1005                    config_value(data, "mysql host", CONFIG_HOST_DEFAULT),
1006                    config_value(data, "mysql user", CONFIG_USER_DEFAULT),
1007                    config_value(data, "mysql password", CONFIG_PASS_DEFAULT),
1008                    config_value(data, "mysql database", CONFIG_DB_DEFAULT),
1009                    xatol(config_value(data, "mysql port", CONFIG_PORT_DEFAULT))));
1010
1011         /* Do the mysql initialization */
1012         data->handle = mysql_init(NULL);
1013         if (!data->handle) {
1014                 DEBUG(0, ("Failed to connect to server\n"));
1015                 return NT_STATUS_UNSUCCESSFUL;
1016         }
1017         /* Process correct entry in $HOME/.my.conf */
1018         if (!mysql_real_connect(data->handle,
1019                         config_value(data, "mysql host", CONFIG_HOST_DEFAULT),
1020                         config_value(data, "mysql user", CONFIG_USER_DEFAULT),
1021                         config_value(data, "mysql password", CONFIG_PASS_DEFAULT),
1022                         config_value(data, "mysql database", CONFIG_DB_DEFAULT),
1023                         xatol(config_value (data, "mysql port", CONFIG_PORT_DEFAULT)), 
1024                         NULL, 0)) {
1025                 DEBUG(0,
1026                           ("Failed to connect to mysql database: error: %s\n",
1027                            mysql_error(data->handle)));
1028                 return NT_STATUS_UNSUCCESSFUL;
1029         }
1030         
1031         DEBUG(5, ("Connected to mysql db\n"));
1032
1033         return NT_STATUS_OK;
1034 }