More strlcat/strlcpy truncate checks.
[amitay/samba.git] / source3 / auth / auth_script.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Call out to a shell script for an authentication check.
5
6    Copyright (C) Jeremy Allison 2005.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "auth.h"
24
25 #undef malloc
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_AUTH
29
30 /* Create a string containing the supplied :
31  * domain\n
32  * user\n
33  * ascii hex challenge\n
34  * ascii hex LM response\n
35  * ascii hex NT response\n\0
36  * and execute a shell script to check this.
37  * Allows external programs to create users on demand.
38  * Script returns zero on success, non-zero on fail.
39  */
40
41 static NTSTATUS script_check_user_credentials(const struct auth_context *auth_context,
42                                         void *my_private_data, 
43                                         TALLOC_CTX *mem_ctx,
44                                         const struct auth_usersupplied_info *user_info,
45                                         struct auth_serversupplied_info **server_info)
46 {
47         const char *script = lp_parm_const_string( GLOBAL_SECTION_SNUM, "auth_script", "script", NULL);
48         char *secret_str;
49         size_t secret_str_len;
50         char hex_str[49];
51         int ret, i;
52
53         if (!script) {
54                 return NT_STATUS_INVALID_PARAMETER;
55         }
56
57         if (!user_info) {
58                 return NT_STATUS_INVALID_PARAMETER;
59         }
60
61         if (!auth_context) {
62                 DEBUG(3,("script_check_user_credentials: no auth_info !\n"));
63                 return NT_STATUS_INVALID_PARAMETER;
64         }               
65
66         secret_str_len = strlen(user_info->mapped.domain_name) + 1 +
67                         strlen(user_info->client.account_name) + 1 +
68                         16 + 1 + /* 8 bytes of challenge going to 16 */
69                         48 + 1 + /* 24 bytes of challenge going to 48 */
70                         48 + 1;
71
72         secret_str = (char *)malloc(secret_str_len);
73         if (!secret_str) {
74                 return NT_STATUS_NO_MEMORY;
75         }
76
77         if (strlcpy( secret_str, user_info->mapped.domain_name, secret_str_len) >= secret_str_len) {
78                 /* Truncate. */
79                 goto cat_out;
80         }
81         if (strlcat( secret_str, "\n", secret_str_len) >= secret_str_len) {
82                 /* Truncate. */
83                 goto cat_out;
84         }
85         if (strlcat( secret_str, user_info->client.account_name, secret_str_len) >= secret_str_len) {
86                 /* Truncate. */
87                 goto cat_out;
88         }
89         if (strlcat( secret_str, "\n", secret_str_len) >= secret_str_len) {
90                 /* Truncate. */
91                 goto cat_out;
92         }
93
94         for (i = 0; i < 8; i++) {
95                 slprintf(&hex_str[i*2], 3, "%02X", auth_context->challenge.data[i]);
96         }
97         if (strlcat( secret_str, hex_str, secret_str_len) >= secret_str_len) {
98                 /* Truncate. */
99                 goto cat_out;
100         }
101         if (strlcat( secret_str, "\n", secret_str_len) >= secret_str_len) {
102                 /* Truncate. */
103                 goto cat_out;
104         }
105
106         if (user_info->password.response.lanman.data) {
107                 for (i = 0; i < 24; i++) {
108                         slprintf(&hex_str[i*2], 3, "%02X", user_info->password.response.lanman.data[i]);
109                 }
110                 if (strlcat( secret_str, hex_str, secret_str_len) >= secret_str_len) {
111                         /* Truncate. */
112                         goto cat_out;
113                 }
114         }
115         if (strlcat( secret_str, "\n", secret_str_len) >= secret_str_len) {
116                 /* Truncate. */
117                 goto cat_out;
118         }
119
120         if (user_info->password.response.nt.data) {
121                 for (i = 0; i < 24; i++) {
122                         slprintf(&hex_str[i*2], 3, "%02X", user_info->password.response.nt.data[i]);
123                 }
124                 if (strlcat( secret_str, hex_str, secret_str_len) >= secret_str_len) {
125                         /* Truncate. */
126                         goto cat_out;
127                 }
128         }
129         if (strlcat( secret_str, "\n", secret_str_len) >= secret_str_len) {
130                 /* Truncate. */
131                 goto cat_out;
132         }
133
134         DEBUG(10,("script_check_user_credentials: running %s with parameters:\n%s\n",
135                 script, secret_str ));
136
137         ret = smbrunsecret( script, secret_str);
138
139         SAFE_FREE(secret_str);
140
141         if (ret) {
142                 DEBUG(1,("script_check_user_credentials: failed to authenticate %s\\%s\n",
143                         user_info->mapped.domain_name, user_info->client.account_name ));
144                 /* auth failed. */
145                 return NT_STATUS_NO_SUCH_USER;
146         }
147
148         /* Cause the auth system to keep going.... */
149         return NT_STATUS_NOT_IMPLEMENTED;
150
151   cat_out:
152
153         SAFE_FREE(secret_str);
154         return NT_STATUS_NO_MEMORY;
155 }
156
157 /* module initialisation */
158 static NTSTATUS auth_init_script(struct auth_context *auth_context, const char *param, auth_methods **auth_method) 
159 {
160         struct auth_methods *result;
161
162         result = talloc_zero(auth_context, struct auth_methods);
163         if (result == NULL) {
164                 return NT_STATUS_NO_MEMORY;
165         }
166         result->name = "script";
167         result->auth = script_check_user_credentials;
168
169         if (param && *param) {
170                 /* we load the 'fallback' module - if script isn't here, call this
171                    module */
172                 auth_methods *priv;
173                 if (!load_auth_module(auth_context, param, &priv)) {
174                         return NT_STATUS_UNSUCCESSFUL;
175                 }
176                 result->private_data = (void *)priv;
177         }
178
179         *auth_method = result;
180         return NT_STATUS_OK;
181 }
182
183 NTSTATUS auth_script_init(void);
184 NTSTATUS auth_script_init(void)
185 {
186         return smb_register_auth(AUTH_INTERFACE_VERSION, "script", auth_init_script);
187 }