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