1 /*------------------------------------------------------------------
2  * strncpy_s.c
3  *
4  * October 2008, Bo Berry
5  *
6  * Copyright (c) 2008-2011 by Cisco Systems, Inc
7  * All rights reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person
10  * obtaining a copy of this software and associated documentation
11  * files (the "Software"), to deal in the Software without
12  * restriction, including without limitation the rights to use,
13  * copy, modify, merge, publish, distribute, sublicense, and/or
14  * sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following
16  * conditions:
17  *
18  * The above copyright notice and this permission notice shall be
19  * included in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28  * OTHER DEALINGS IN THE SOFTWARE.
29  *------------------------------------------------------------------
30  */
31 
32 #include "safeclib_private.h"
33 #include "safe_str_constraint.h"
34 #include "safe_str_lib.h"
35 
36 
37 /*
38  * NAME
39  *    strncpy_s
40  *
41  * SYNOPSIS
42  *    #include "safe_str_lib.h"
43  *    errno_t
44  *    strncpy_s(char *dest, rsize_t dmax, const char *src, rsize_t slen)
45  *
46  * DESCRIPTION
47  *    The strncpy_s function copies not more than slen successive characters
48  *    (characters that follow a null character are not copied) from the
49  *    array pointed to by src to the array pointed to by dest. If no null
50  *    character was copied from src, then dest[n] is set to a null character.
51  *
52  *    All elements following the terminating null character (if any)
53  *    written by strncpy_s in the array of dmax characters pointed to
54  *    by dest take on the null value when strncpy_s returns.
55  *
56  * Specicified in:
57  *    ISO/IEC TR 24731-1, Programming languages, environments
58  *    and system software interfaces, Extensions to the C Library,
59  *    Part I: Bounds-checking interfaces
60  *
61  * INPUT PARAMETERS
62  *    dest      pointer to string that will be replaced by src.
63  *              The resulting string is null terminated.
64  *
65  *    dmax      restricted maximum length of the resulting dest,
66  *              including the null
67  *
68  *    src       pointer to the string that will be copied
69  *              to string dest
70  *
71  *    slen      the maximum number of characters to copy from src
72  *
73  * OUTPUT PARAMETERS
74  *    dest      updated with src string
75  *
76  * RUNTIME CONSTRAINTS
77  *    Neither dmax nor slen shall be equal to zero.
78  *    Neither dmax nor slen shall be equal zero.
79  *    Neither dmax nor slen shall be greater than RSIZE_MAX_STR.
80  *    If slen is either greater than or equal to dmax, then dmax
81  *     should be more than strnlen_s(src,dmax)
82  *    Copying shall not take place between objects that overlap.
83  *    If there is a runtime-constraint violation, then if dest
84  *       is not a null pointer and dmax greater than RSIZE_MAX_STR,
85  *       then strncpy_s nulls dest.
86  *
87  * RETURN VALUE
88  *    EOK        successful operation, the characters in src were copied
89  *                  to dest and the result is null terminated.
90  *    ESNULLP    NULL pointer
91  *    ESZEROL    zero length
92  *    ESLEMAX    length exceeds max limit
93  *    ESOVRLP    strings overlap
94  *    ESNOSPC    not enough space to copy src
95  *
96  * ALSO SEE
97  *    strcat_s(), strncat_s(), strcpy_s()
98  *-
99  */
100 errno_t
strncpy_s(char * dest,rsize_t dmax,const char * src,rsize_t slen)101 strncpy_s (char *dest, rsize_t dmax, const char *src, rsize_t slen)
102 {
103     rsize_t orig_dmax;
104     char *orig_dest;
105     const char *overlap_bumper;
106 
107     if (dest == NULL) {
108         invoke_safe_str_constraint_handler("strncpy_s: dest is null",
109                    NULL, ESNULLP);
110         return RCNEGATE(ESNULLP);
111     }
112 
113     if (dmax == 0) {
114         invoke_safe_str_constraint_handler("strncpy_s: dmax is 0",
115                    NULL, ESZEROL);
116         return RCNEGATE(ESZEROL);
117     }
118 
119     if (dmax > RSIZE_MAX_STR) {
120         invoke_safe_str_constraint_handler("strncpy_s: dmax exceeds max",
121                    NULL, ESLEMAX);
122         return RCNEGATE(ESLEMAX);
123     }
124 
125     /* hold base in case src was not copied */
126     orig_dmax = dmax;
127     orig_dest = dest;
128 
129     if (src == NULL) {
130         handle_error(orig_dest, orig_dmax, "strncpy_s: "
131                      "src is null",
132                      ESNULLP);
133         return RCNEGATE(ESNULLP);
134     }
135 
136     if (slen == 0) {
137         handle_error(orig_dest, orig_dmax, "strncpy_s: "
138                      "slen is zero",
139                      ESZEROL);
140         return RCNEGATE(ESZEROL);
141     }
142 
143     if (slen > RSIZE_MAX_STR) {
144         handle_error(orig_dest, orig_dmax, "strncpy_s: "
145                      "slen exceeds max",
146                      ESLEMAX);
147         return RCNEGATE(ESLEMAX);
148     }
149 
150 
151    if (dest < src) {
152        overlap_bumper = src;
153 
154         while (dmax > 0) {
155             if (dest == overlap_bumper) {
156                 handle_error(orig_dest, orig_dmax, "strncpy_s: "
157                         "overlapping objects",
158                         ESOVRLP);
159                 return RCNEGATE(ESOVRLP);
160             }
161 
162 	    if (slen == 0) {
163                 /*
164                  * Copying truncated to slen chars.  Note that the TR says to
165                  * copy slen chars plus the null char.  We null the slack.
166                  */
167 #ifdef SAFECLIB_STR_NULL_SLACK
168                 while (dmax) { *dest = '\0'; dmax--; dest++; }
169 #else
170                 *dest = '\0';
171 #endif
172                 return RCNEGATE(EOK);
173             }
174 
175             *dest = *src;
176             if (*dest == '\0') {
177 #ifdef SAFECLIB_STR_NULL_SLACK
178                 /* null slack */
179                 while (dmax) { *dest = '\0'; dmax--; dest++; }
180 #endif
181                 return RCNEGATE(EOK);
182             }
183 
184             dmax--;
185             slen--;
186             dest++;
187             src++;
188         }
189 
190     } else {
191         overlap_bumper = dest;
192 
193         while (dmax > 0) {
194             if (src == overlap_bumper) {
195                 handle_error(orig_dest, orig_dmax, "strncpy_s: "
196                         "overlapping objects",
197                         ESOVRLP);
198                 return RCNEGATE(ESOVRLP);
199             }
200 
201 	    if (slen == 0) {
202                 /*
203                  * Copying truncated to slen chars.  Note that the TR says to
204                  * copy slen chars plus the null char.  We null the slack.
205                  */
206 #ifdef SAFECLIB_STR_NULL_SLACK
207                 while (dmax) { *dest = '\0'; dmax--; dest++; }
208 #else
209                 *dest = '\0';
210 #endif
211                 return RCNEGATE(EOK);
212             }
213 
214             *dest = *src;
215             if (*dest == '\0') {
216 #ifdef SAFECLIB_STR_NULL_SLACK
217                 /* null slack */
218                 while (dmax) { *dest = '\0'; dmax--; dest++; }
219 #endif
220                 return RCNEGATE(EOK);
221             }
222 
223             dmax--;
224             slen--;
225             dest++;
226             src++;
227         }
228     }
229 
230     /*
231      * the entire src was not copied, so zero the string
232      */
233     handle_error(orig_dest, orig_dmax, "strncpy_s: not enough "
234                  "space for src",
235                  ESNOSPC);
236     return RCNEGATE(ESNOSPC);
237 }
238 EXPORT_SYMBOL(strncpy_s)
239