798cb3fff74c17ca9a711b1a9bcc7dee3fbd6ae3
[samba.git] / source3 / lib / smbldap_util.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    LDAP protocol helper functions for SAMBA
4    Copyright (C) Jean François Micouleau        1998
5    Copyright (C) Gerald Carter                  2001-2003
6    Copyright (C) Shahms King                    2001
7    Copyright (C) Andrew Bartlett                2002-2003
8    Copyright (C) Stefan (metze) Metzmacher      2002-2003
9     
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23    
24 */
25
26 #include "includes.h"
27 #include "smbldap.h"
28
29 /**********************************************************************
30  Add the sambaDomain to LDAP, so we don't have to search for this stuff
31  again.  This is a once-add operation for now.
32
33  TODO:  Add other attributes, and allow modification.
34 *********************************************************************/
35 static NTSTATUS add_new_domain_info(struct smbldap_state *ldap_state, 
36                                     const char *domain_name) 
37 {
38         fstring sid_string;
39         fstring algorithmic_rid_base_string;
40         pstring filter, dn;
41         LDAPMod **mods = NULL;
42         int rc;
43         int ldap_op;
44         LDAPMessage *result = NULL;
45         int num_result;
46         const char **attr_list;
47         uid_t u_low, u_high;
48         gid_t g_low, g_high;
49         uint32 rid_low, rid_high;
50
51         slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))", 
52                   get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
53                   domain_name, LDAP_OBJ_DOMINFO);
54
55         attr_list = get_attr_list( dominfo_attr_list );
56         rc = smbldap_search_suffix(ldap_state, filter, attr_list, &result);
57         free_attr_list( attr_list );
58
59         if (rc != LDAP_SUCCESS) {
60                 return NT_STATUS_UNSUCCESSFUL;
61         }
62
63         num_result = ldap_count_entries(ldap_state->ldap_struct, result);
64         
65         if (num_result > 1) {
66                 DEBUG (0, ("More than domain with that name exists: bailing out!\n"));
67                 ldap_msgfree(result);
68                 return NT_STATUS_UNSUCCESSFUL;
69         }
70         
71         /* Check if we need to add an entry */
72         DEBUG(3,("Adding new domain\n"));
73         ldap_op = LDAP_MOD_ADD;
74
75         pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
76                 domain_name, lp_ldap_suffix());
77
78         /* Free original search */
79         ldap_msgfree(result);
80
81         /* make the changes - the entry *must* not already have samba attributes */
82         smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
83                 domain_name);
84
85         /* If we don't have an entry, then ask secrets.tdb for what it thinks.  
86            It may choose to make it up */
87
88         sid_to_string(sid_string, get_global_sam_sid());
89         smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), sid_string);
90
91         slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string) - 1, "%i", algorithmic_rid_base());
92         smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), 
93                         algorithmic_rid_base_string);
94         smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO);
95         
96         /* add the sambaNext[User|Group]Rid attributes if the idmap ranges are set.
97            TODO: fix all the places where the line between idmap and normal operations
98            needed by smbd gets fuzzy   --jerry 2003-08-11                              */
99         
100         if ( lp_idmap_uid(&u_low, &u_high) && lp_idmap_gid(&g_low, &g_high)
101                 && get_free_rid_range(&rid_low, &rid_high) ) 
102         {
103                 fstring rid_str;
104                 
105                 fstr_sprintf( rid_str, "%i", rid_high|USER_RID_TYPE );
106                 DEBUG(10,("setting next available user rid [%s]\n", rid_str));
107                 smbldap_set_mod(&mods, LDAP_MOD_ADD, 
108                         get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), 
109                         rid_str);
110                         
111                 fstr_sprintf( rid_str, "%i", rid_high|GROUP_RID_TYPE );
112                 DEBUG(10,("setting next available group rid [%s]\n", rid_str));
113                 smbldap_set_mod(&mods, LDAP_MOD_ADD, 
114                         get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), 
115                         rid_str);
116                 
117         }
118
119
120         switch(ldap_op)
121         {
122         case LDAP_MOD_ADD: 
123                 rc = smbldap_add(ldap_state, dn, mods);
124                 break;
125         case LDAP_MOD_REPLACE: 
126                 rc = smbldap_modify(ldap_state, dn, mods);
127                 break;
128         default:        
129                 DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
130                 return NT_STATUS_INVALID_PARAMETER;
131         }
132         
133         if (rc!=LDAP_SUCCESS) {
134                 char *ld_error = NULL;
135                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
136                 DEBUG(1,("failed to %s domain dn= %s with: %s\n\t%s\n",
137                        ldap_op == LDAP_MOD_ADD ? "add" : "modify",
138                        dn, ldap_err2string(rc),
139                        ld_error?ld_error:"unknown"));
140                 SAFE_FREE(ld_error);
141
142                 ldap_mods_free(mods, True);
143                 return NT_STATUS_UNSUCCESSFUL;
144         }
145
146         DEBUG(2,("added: domain = %s in the LDAP database\n", domain_name));
147         ldap_mods_free(mods, True);
148         return NT_STATUS_OK;
149 }
150
151 /**********************************************************************
152 Search for the domain info entry
153 *********************************************************************/
154 NTSTATUS smbldap_search_domain_info(struct smbldap_state *ldap_state,
155                                     LDAPMessage ** result, const char *domain_name,
156                                     BOOL try_add)
157 {
158         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
159         pstring filter;
160         int rc;
161         const char **attr_list;
162         int count;
163
164         pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
165                 LDAP_OBJ_DOMINFO,
166                 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
167                 domain_name);
168
169         DEBUG(2, ("Searching for:[%s]\n", filter));
170
171         attr_list = get_attr_list( dominfo_attr_list );
172         rc = smbldap_search_suffix(ldap_state, filter, attr_list , result);
173         free_attr_list( attr_list );
174
175         if (rc != LDAP_SUCCESS) {
176                 DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
177                 DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter));
178                 goto failed;
179         }
180
181         count = ldap_count_entries(ldap_state->ldap_struct, *result);
182
183         if (count == 1)
184                 return NT_STATUS_OK;
185
186         ldap_msgfree(*result);
187         *result = NULL;
188         
189         if (count < 1) {
190
191                 DEBUG(3, ("Got no domain info entries for domain\n"));
192
193                 if (!try_add)
194                         goto failed;
195
196                 status = add_new_domain_info(ldap_state, domain_name);
197                 if (!NT_STATUS_IS_OK(status)) {
198                         DEBUG(0, ("Adding domain info for %s failed with %s\n", 
199                                 domain_name, nt_errstr(status)));
200                         goto failed;
201                 }
202                         
203                 return smbldap_search_domain_info(ldap_state, result, domain_name, False);
204                 
205         } 
206         
207         if (count > 1 ) {
208         
209                 DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n",
210                           count, domain_name));
211                 goto failed;
212         }
213
214 failed:
215         return status;
216         
217 }
218