s3: in sys_popen(), validate input before opening the pipe.
[kai/samba.git] / source3 / lib / afs_settoken.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  Generate AFS tickets
4  *  Copyright (C) Volker Lendecke 2004
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *  
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *  
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21
22 #ifdef WITH_FAKE_KASERVER
23
24 #define NO_ASN1_TYPEDEFS 1
25
26 #include "system/filesys.h"
27
28 #include <afs/param.h>
29 #include <afs/stds.h>
30 #include <afs/afs.h>
31 #include <afs/auth.h>
32 #include <afs/venus.h>
33 #include <asm/unistd.h>
34 #include <openssl/des.h>
35 #include <sys/syscall.h>
36
37 int afs_syscall( int subcall,
38           const char * path,
39           int cmd,
40           char * cmarg,
41           int follow)
42 {
43 /*
44         return( syscall( SYS_afs_syscall, subcall, path, cmd, cmarg, follow));
45 */
46         int errcode;
47         int proc_afs_file;
48         struct afsprocdata afs_syscall_data;
49         afs_syscall_data.syscall = subcall;
50         afs_syscall_data.param1 = (long)path;
51         afs_syscall_data.param2 = cmd;
52         afs_syscall_data.param3 = (long)cmarg;
53         afs_syscall_data.param4 = follow;
54         proc_afs_file = open(PROC_SYSCALL_FNAME, O_RDWR);
55         if (proc_afs_file < 0)
56                 proc_afs_file = open(PROC_SYSCALL_ARLA_FNAME, O_RDWR);
57         if (proc_afs_file < 0)
58                 return -1;
59         errcode = ioctl(proc_afs_file, VIOC_SYSCALL, &afs_syscall_data);
60         close(proc_afs_file);
61         return errcode;
62 }
63
64 struct ClearToken {
65         uint32 AuthHandle;
66         char HandShakeKey[8];
67         uint32 ViceId;
68         uint32 BeginTimestamp;
69         uint32 EndTimestamp;
70 };
71
72 static bool afs_decode_token(const char *string, char **cell,
73                              DATA_BLOB *ticket, struct ClearToken *ct)
74 {
75         DATA_BLOB blob;
76         struct ClearToken result_ct;
77         char *saveptr;
78
79         char *s = SMB_STRDUP(string);
80
81         char *t;
82
83         if ((t = strtok_r(s, "\n", &saveptr)) == NULL) {
84                 DEBUG(10, ("strtok_r failed\n"));
85                 return false;
86         }
87
88         *cell = SMB_STRDUP(t);
89
90         if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
91                 DEBUG(10, ("strtok_r failed\n"));
92                 return false;
93         }
94
95         if (sscanf(t, "%u", &result_ct.AuthHandle) != 1) {
96                 DEBUG(10, ("sscanf AuthHandle failed\n"));
97                 return false;
98         }
99                 
100         if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
101                 DEBUG(10, ("strtok_r failed\n"));
102                 return false;
103         }
104
105         blob = base64_decode_data_blob(t);
106
107         if ( (blob.data == NULL) ||
108              (blob.length != sizeof(result_ct.HandShakeKey) )) {
109                 DEBUG(10, ("invalid key: %x/%lu\n", (uint8_t)*blob.data,
110                            (unsigned long) blob.length));
111                 return false;
112         }
113
114         memcpy(result_ct.HandShakeKey, blob.data, blob.length);
115
116         data_blob_free(&blob);
117
118         if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
119                 DEBUG(10, ("strtok_r failed\n"));
120                 return false;
121         }
122
123         if (sscanf(t, "%u", &result_ct.ViceId) != 1) {
124                 DEBUG(10, ("sscanf ViceId failed\n"));
125                 return false;
126         }
127                 
128         if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
129                 DEBUG(10, ("strtok_r failed\n"));
130                 return false;
131         }
132
133         if (sscanf(t, "%u", &result_ct.BeginTimestamp) != 1) {
134                 DEBUG(10, ("sscanf BeginTimestamp failed\n"));
135                 return false;
136         }
137                 
138         if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
139                 DEBUG(10, ("strtok_r failed\n"));
140                 return false;
141         }
142
143         if (sscanf(t, "%u", &result_ct.EndTimestamp) != 1) {
144                 DEBUG(10, ("sscanf EndTimestamp failed\n"));
145                 return false;
146         }
147                 
148         if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) {
149                 DEBUG(10, ("strtok_r failed\n"));
150                 return false;
151         }
152
153         blob = base64_decode_data_blob(t);
154
155         if (blob.data == NULL) {
156                 DEBUG(10, ("Could not get ticket\n"));
157                 return false;
158         }
159
160         *ticket = blob;
161         *ct = result_ct;
162
163         return true;
164 }
165
166 /*
167   Put an AFS token into the Kernel so that it can authenticate against
168   the AFS server. This assumes correct local uid settings.
169
170   This is currently highly Linux and OpenAFS-specific. The correct API
171   call for this would be ktc_SetToken. But to do that we would have to
172   import a REALLY big bunch of libraries which I would currently like
173   to avoid. 
174 */
175
176 static bool afs_settoken(const char *cell,
177                          const struct ClearToken *ctok,
178                          DATA_BLOB ticket)
179 {
180         int ret;
181         struct {
182                 char *in, *out;
183                 uint16 in_size, out_size;
184         } iob;
185
186         char buf[1024];
187         char *p = buf;
188         int tmp;
189
190         memcpy(p, &ticket.length, sizeof(uint32));
191         p += sizeof(uint32);
192         memcpy(p, ticket.data, ticket.length);
193         p += ticket.length;
194
195         tmp = sizeof(struct ClearToken);
196         memcpy(p, &tmp, sizeof(uint32));
197         p += sizeof(uint32);
198         memcpy(p, ctok, tmp);
199         p += tmp;
200
201         tmp = 0;
202
203         memcpy(p, &tmp, sizeof(uint32));
204         p += sizeof(uint32);
205
206         tmp = strlen(cell);
207         if (tmp >= MAXKTCREALMLEN) {
208                 DEBUG(1, ("Realm too long\n"));
209                 return false;
210         }
211
212         strncpy(p, cell, tmp);
213         p += tmp;
214         *p = 0;
215         p +=1;
216
217         iob.in = buf;
218         iob.in_size = PTR_DIFF(p,buf);
219         iob.out = buf;
220         iob.out_size = sizeof(buf);
221
222 #if 0
223         file_save("/tmp/ioctlbuf", iob.in, iob.in_size);
224 #endif
225
226         ret = afs_syscall(AFSCALL_PIOCTL, 0, VIOCSETTOK, (char *)&iob, 0);
227
228         DEBUG(10, ("afs VIOCSETTOK returned %d\n", ret));
229         return (ret == 0);
230 }
231
232 bool afs_settoken_str(const char *token_string)
233 {
234         DATA_BLOB ticket;
235         struct ClearToken ct;
236         bool result;
237         char *cell;
238
239         if (!afs_decode_token(token_string, &cell, &ticket, &ct))
240                 return false;
241
242         if (geteuid() != sec_initial_uid())
243                 ct.ViceId = getuid();
244
245         result = afs_settoken(cell, &ct, ticket);
246
247         SAFE_FREE(cell);
248         data_blob_free(&ticket);
249
250         return result;
251 }
252
253 #else
254
255 bool afs_settoken_str(const char *token_string)
256 {
257         return false;
258 }
259
260 #endif